『A Fast Resection-Intersection Method for the Known Rotation Problem』を読む

adventar.org

これはプロラボアドベントカレンダー7日目の記事です。

皆さん卒研の進捗どうですか。僕は進捗が生えません。

特徴点ベースのVisual SLAMについての論文『A Fast Resection-Intersection Method for the Known Rotation Problem』*1を読んだので記事を書きます。

SLAMとはRGBカメラ(普通のカメラ)やレーザーなどのセンサーをロボットや車などに載せて、自己位置の推定と周りの地図の作成を行うことです。Visual SLAMはその中でも画像を入力とするものを指します。
下の動画はORB-SLAM2というOSSのSLAMを動かしている様子です。

www.youtube.com

論文の内容

『A Fast Resection-Intersection Method for the Known Rotation Problem』では画像と既知のカメラの回転から、シーンポイントの3次元座標とカメラの3次元座標を求めるKnown Rotation Problemという問題を解きます。Known Rotation Problemは次のように定式化されます。


\begin{equation}
\min_{\{\boldsymbol{X}_i\}, \{\boldsymbol{t}_j\}}
\max_{i,j}
\|
\boldsymbol{u}_{i,j} - f(\boldsymbol{X}_i | \boldsymbol{R}_j, \boldsymbol{t}_j)
\|_2 \\
s.t. \qquad \boldsymbol{R}^3_j \boldsymbol{s}_k + \boldsymbol{t}_j > 0 \ \forall{j, k}
\end{equation}
 \boldsymbol{R}_j \boldsymbol{t}_j はそれぞれj番目のフレームにおけるカメラの回転と位置、 \boldsymbol{s}_k k番目のシーンポイントの3次元座標、 \boldsymbol{u}_{j,k} j番目の画像から見た k番目のシーンポイントの2次元座標です。
 f(\boldsymbol{X}_i | \boldsymbol{R}_j, \boldsymbol{t}_j) はシーンポイント \boldsymbol{X}_i を回転と位置が \boldsymbol{R}_j \boldsymbol{t}_jであるカメラに投影する関数です。カメラの焦点距離とかで変わります。
制約不等式は、シーンポイントがカメラの前にあることを表しています(カメラの前にないとカメラに写りません)。

 \{ \boldsymbol{s}_k \}は固定して \{ \boldsymbol{t}_j \}を最適化するRes、 \{ \boldsymbol{t}_j \}は固定して \{ \boldsymbol{s}_k \}を最適化するIntの2つの問題に分けて解きます。
どちらの問題も、
\begin{eqnarray}
r_i(\boldsymbol{x}) = \frac
{
\|
\boldsymbol{A}_i \boldsymbol{x} + \boldsymbol{b}_i
\|_2
}
{
\boldsymbol{c}^T_i \boldsymbol{x} + d_i
}
\end{eqnarray}
を使って
\begin{eqnarray}
\min_{\boldsymbol{x} \in \mathbb{R}^3 }
\max_{i}
r_i(\boldsymbol{x}) \\
s.t. \qquad \boldsymbol{c}^T_i \boldsymbol{x} + d_i > 0 \ \forall{i}
\end{eqnarray}
と表せます。


この問題を解くために目的関数
\begin{eqnarray}
\max_{i}
r_i(\boldsymbol{\hat{x}})
\end{eqnarray}
の値が減少するように
\begin{eqnarray}
\boldsymbol{\hat{x}} \leftarrow \boldsymbol{\hat{x}} + \alpha \boldsymbol{\lambda}
\end{eqnarray}
 \boldsymbol{\hat{x}}を繰り返し更新します。目的関数を減少させるベクトル \boldsymbol{\lambda}を求めてそれに適当な正の実数 \alphaを掛けています

まず、 \boldsymbol{\lambda}を求めます。
 r_i(\boldsymbol{x})の最大値を最小化するので、 r_i(\boldsymbol{x})の中でも最大値を取る r_l(\boldsymbol{x})だけを考えます。各 r_l(\boldsymbol{x})について
\begin{eqnarray}
\boldsymbol{g}_l = - \frac
{
\nabla r_l(\boldsymbol{\hat{x}})
}
{
\|
\nabla r_l(\boldsymbol{\hat{x}})
\|_2
}
\end{eqnarray}
を計算し、 \boldsymbol{g}_lを包含する最小の球の中心が目的関数を最も減少させる方向なので*2、これを \boldsymbol{\lambda}とします。

次に \alphaを求めます。
 r_i \alphaの関数と考えると

\begin{eqnarray}
r_i(\alpha) = \frac
{
\|
\boldsymbol{A}_i (\boldsymbol{\hat{x}} + \alpha \boldsymbol{\lambda}) + \boldsymbol{b}_i
\|_2
}
{
\boldsymbol{c}^T_i (\boldsymbol{\hat{x}} + \alpha \boldsymbol{\lambda}) + d_i
}
\end{eqnarray}
となって \alphaを求める問題は
\begin{eqnarray}
\min_{\alpha \in \mathbb{R}_+ }
\max_{i}
r_i(\alpha) \\
s.t. \qquad \boldsymbol{c}^T_i (\boldsymbol{\hat{x}} + \alpha \boldsymbol{\lambda}) + d_i > 0 \ \forall{i}
\end{eqnarray}
と表せます。
目的関数は最小値の両側でそれぞれ単調増加か単調減少なので、注目している点からちょっとずらした点を見て減少しているか増加しているか考え、 \alphaを二分探索します。

実験

f:id:gedorinku:20191224224847p:plain
FDMがこの論文の手法です。速くなった。

最後に

間違ったことを書いていても僕を筑後川に沈めたりせずに教えてもらえるとうれしいです。

明日(12/8)の記事の担当ははと君です。楽しみですね。

*1:Q. Zhang, T.-J. Chin, and H. M. Le, “A fast resection-intersection method for the known rotation problem,” in CVPR, 2018, https://arxiv.org/pdf/1902.03747.pdf

*2:証明は論文を読んでほしいです

Wantedlyのサマーインターンに参加した

8/20〜9/21までの5週間、Wantedlyのサマーインターンに参加しました。

wantedlyinc.com

本来は9/7までの予定でしたが、期間を延長していただきました(後述)。

やったこと

パフォーマンスの改善

Wantedly Peopleのoptionsという設定値を管理するマイクロサービスのパフォーマンスを改善することになりました。 optionsについては資料が公開されています。

speakerdeck.com

最初の1週間はoptionsに慣れるためにリファクタリングのようなことをして、その後の2週間でボトルネックの調査と実装をしました。 optionsはDBとのラウンドトリップタイムがボトルネックになっていたので、DBのスキーマやクエリを改善していきました。 optionsはGoで書かれていますがDBのマイグレーションRubyでされていたので、Rubyバッチ処理を書いたりもしました。

Rubyを書いた経験は高専1年生の時に2、3日でTwitter APIRailsを使ったwebアプリを作った程度でしたが、なんとかなりました。

最後にmasterにマージされ、本番環境でoptionsのレスポンスタイムが約1/2になりテンションが上がりました。

また、最後の週にメンターさんからインターンを延長しないかと誘われたので、インターンを2週間延長することに決めました。

マイクロサービスへの切り出し

延長した2週間のインターンでは、Wantedly VisitとWantedly PeopleのRailsアプリに実装されている機能を共通のマイクロサービスに切り出すタスクに取り組みました。 1週間でWantedly Visit、People、ChatのRailsアプリの切り出す機能のコードを読み、マイクロサービスのAPIを設計しました。特にWantedly Visitは、Wantedlyの歴史が積み重なったモノリシックで巨大なRailsアプリなので、読み応えがあります。

最後の週でマイクロサービスのAPIを実装に取り掛かりました。 この時に、DBマイグレーションツールの ridgepole を新しく導入してみました。 ridgepole はRubyDSLでDBのschemaを書けばいい感じに差分を見てマイグレーションしてくれるので、シンプルで使いやすいかなと思います。 また、ORMには SQLBoiler を使いました。

最後の2日でWantedly VisitとPeopleのRailsアプリを一部書き換えてデモ動画を撮影し、金曜日の全社員ミィーティング「Demo Day」で発表させていただきました。

ご飯

オフィスのある白金台はおしゃれな飲食店が多いです。ちょっと値段が高いので気をつけましょう。 f:id:gedorinku:20180930180325j:plain

時々オフィスで夕ご飯が食べられるので、ほぼ毎回食べてました。 f:id:gedorinku:20180930180122j:plain

まとめ

最初の3週間はほとんどずっとコードを書いていて、その期間だけで200 commitsくらいできたし、ちゃんと動けばproductionに反映されるのですごく楽しかったです。 f:id:gedorinku:20180930172204p:plain

また、インターン中にSQLBoilerのバグを踏んだので、帰ってからプルリクエストを出したらマージされました。

github.com

このインターンでは交通費と宿泊場所と日給1.5万円がいただけました。メンターさんも1人か2人につき1人ついていただけて体験が良かったと思います。 学校に募集が来る会社以外でインターン先を探すプロラボ部員とかは、検討してみてください。

最後に、5週間メンターをしてくださった @izumin5210 さんありがとうございました。

高専カンファレンス in 東京 2018に参加した

kosenconf.tokyo

高専カンファレンス in 東京 2018に参加してきました。
部内戦の準備などがあって、ブログを公開するのが遅れてすみません。

福岡という田舎に住んでるので普通は東京にあるイベントなどには参加できないのですが、参加費支援制度があり、応募フォームに飛行機代を書いたら交通費全額+宿泊代が支給されました。ありがとうございます。

以下に特に印象に残った発表などについて書きます。

 

docs.google.com

最初の発表は、湊川あいさんによる『実践!イラストでわかりやすく表現する技術』です。

  1. つまづいたことをメモ
  2. 過去の自分に答えてあげる
  3. 表現する
  4. 発信する

の流れで制作されているようですが、慣れてしまうとつまづいたことも忘れてしまうので、1は結構大事だなぁと思いました。
また、

  • 抽象化
  • 比喩
  • 具体化
  • 事例

の4つの方向から物事を説明すると良い、ということは僕も人に説明する時に使っていきたいです。とても勉強になりました。

 

お昼はお弁当とサンドイッチが用意されてました。僕はサンドイッチを選んで食べましたが、結構量があってお腹いっぱいになりました。
午後にLTをする予定だったので、机に座ってその準備をしていました。(良くない)

 

午後の最初の発表はきゅんくんさんによる『今すぐ始める社会とつながるMake』でした。
ファッションに、ただパタパタ動くロボットの羽を取り入れるとか面白くて好きです。

KYUN_KUN Web | Robotics Fashion Creator

公式サイトで過去の作品が紹介されているので眺めていました。

 

藍月要さんの『高専ラノベのつくりかた』は、一番印象に残るやばい発表でした。
冒頭の「コウセンミミッミ」のクオリティが高くて面白かったです。
本を読んだことはなかったのですが、どのように設定を考えて異世界をつくったのか知ることができました。

午後は2回の休憩を挟んだ後、LTがありました。
ここでは僕も発表させていただきました。
ちょっと失敗してしまって、デモを画面に表示させることができなくて残念です。speakerdeck.com

 

 

その後の懇親会では、沖縄高専卒の方々などたくさんの方に話しかけていただけたので、1人でご飯を黙々と食べる人にならずにすみました。なかなか自分から話しかけられないので嬉しいです。
発表すると自然に交流ができるし話すネタも生まれるので、僕のような人間にとってはこういう意味でも良いことがあるなと思いました。

 

 

Ktorを使う話

はじめに

この記事は、Prolab Advent Calendar 2017の10日目の記事として書かれています。

adventar.org

23時くらいから書きはじめたので、遅刻しました。ごめんなさい。

この記事には、Ktorを使ったプロジェクトの作成方法を書きました。ついでに、Ktorを使った時のテストの書き方も紹介します。 また、記事で作ったアプリのソースコードGithubに置いてあります。 github.com

Ktorとは

Kotlin製のWebフレームワークです。

github.com

最近記事とかも増えてきたので、よいですね。 ちなみに、PCK2017モバイル部門に出場した時に作った作品のバックエンドには、Ktorを使っています。(AndroidアプリもKotlinなので、100%Kotlin???)

Hello World

build.gradle
maven { url "https://dl.bintray.com/kotlin/kotlinx" }
maven { url "https://dl.bintray.com/kotlin/ktor" }

repositoriesに追加したあと、

compile "io.ktor:ktor-server-netty:0.9.0"

dependenciesに追加してください。

gist.github.com

Helloと返すエンドポイントを定義する

gist.github.com

application.conf

あとでテストを書きたいので、application.confをresourcesに追加します。 modulesに先ほどのエンドポイントを定義している拡張関数のパッケージと名前を設定します。 gist.github.com

動かす

メインクラスをio.ktor.server.netty.DevelopmentEngineに設定して起動します。localhost:8080を叩くとHelloという文字列が返されるようになりました。おめでとうございます。

~>curl localhost:8080
Hello

テストの書き方

順番が逆な気がしますが。

build.gradle

先ほど書いたbuild.gradleのdependencies

testCompile "junit:junit:4.12"
testCompile "io.ktor:ktor-server-test-host:$ktor_version"

を追加します。

テストクラス

先ほどのエンドポイントを叩いて、ステータスコードが200 OKであることと、Helloが返されていることをテストしています。 gist.github.com

お疲れ様でした。 f:id:gedorinku:20171210010214p:plain

まとめ

Webアプリを作りたい気持ちになったときに、まだ発展途上っぽいですがKtorを使ってみるのもいいと思います。PCKの時に使ってましたが、Ktorのバージョンをあげたらテストが半分くらい落ちるようになったりしてちょっと怖かったです。PCKの開発が始まったときのKtorのバージョンは0.3.3だったんですが、いつの間にか0.9.0とかになってバージョンアップが早いですね。

すばやく記事を書いたので、次の日の記事が投稿される前にこの記事を投稿できました。広義明日は1年生のfooくんの番です。

AndroidでUriからOkHttpのRequestBodyを作る

Android開発で、Uriが指している画像をRequestBodyに入れてRetrofitでサーバーにPOSTしようとしましたが、解決する途中で様々な問題が出てつまづいたので記事にしました。

 

一般的(??)なRequestBodyの作り方

RequestBody (OkHttp 3.9.0 API)

RequestBodyにはファクトリメソッドが用意されているので、それを使ってインスタンスを作ります。Fileを渡す方法や、byte配列を直接渡す方法があります。

今回はAndroidUriが指しているファイルをRequestBodyに入れたいので、うまくいきません。

解決法1 UriからFileに変換して、Fileを渡す

もっとも簡単そうな解決方法ですが、うまくいかない場合があります。

qiita.com

この記事やこの記事中に貼ってあるStackOverflowにUriからFileに変換する方法が掲載されています。同記事にも書いてありますが、この方法ではカメラを開いて撮影した画像などを指すUriはFileに変換できません。UriによってFileに変換する方法が違うので、UriをFileに変換するのはとてもめんどくさそうです。

 

解決法2 byte配列を渡す

ContentResolverを使ってFileからInputStreamを取得できるので、一旦ファイルの内容をbyte配列に入れてRequestBodyを作る方法です。

Android 画像ファイルを扱う際のFileとUriまとめ - Qiita

やってみましたが、5MBくらいの画像を扱うとOutOfMemoryErrorが発生したり、GCが頻発して重くなりアップロードに50秒くらいかかったりしてうまくいきませんでした。

解決法3 RequestBodyを実装する

既存のファクトリメソッドを使う方法ではうまくいかなさそうなので、自分で実装します。

RequestBodyのcreateメソッドの中には、RequestBodyの抽象メソッドの実装が書かれているので、これを参考にします。

github.com

 

Kotlinで実装しました。

gist.github.com

 

本当はRequestBodyのstaticな拡張関数(KotlinのCompanion objectの拡張関数みたいな??)として定義しようとしました。しかし、RequestBodyのようにCompanion objectを持っていないJavaのクラスの場合、それはできないようです。

もっといい方法や間違いなどあれば、マサカリを投げてください。

うどん

この記事はProlab Advent Calendar 2016の22日目の記事です。

www.adventar.org

 

僕は外食するときに、頻繁にうどんを食べに行くので、うどんについての記事を書こうと思います。

味のレビューについては、食べた直後ではなく思い出しながら書いている上に僕の表現力も低いので、あまり詳しく書けてないですが許してください。

 

正八郎うどん

久留米高専の近くにあります。学校にいるときにご飯がなかったら、とりあえず正八に行きます。

僕は冬限定の煮鶏うどんが好きでした。やわらかい煮鶏は少し甘くて、うどんによく合うのでとても美味しいです。

正八に行くと毎回50円割引券(2枚組)をもらえますが、この割引券を1枚使うとまた2枚組の50円割引券をもらえるので、無限に割引券を増やすことができることで有名です。

しかし、10月初め頃(ちょうどプロコンの出発日)に火事になって全焼してしまいました。煮鶏うどんが食べれなくなってしまったので、結構つらいです。再建はするらしいので、再建されたらまた行きます。

人力うどん

正八郎うどんが火事になってから初めて行きました。学校から一番近いうどん屋がここなので、正八郎が再建されるまでたまに行くと思います。

麺は正八うどんに比べて少しコシがある感じです。鶏肉が食べたかったので、鶏天うどんを食べてみましたが、本当に鶏天がそのままうどんに乗っかっていました(それはそう)。

いろんな具が入ってるスタミナうどんが面白そうなので、次行った時に食べてみようと思います。

丼どん亭

高専プロコンで三重に行ったときに行きました。伊勢神宮内宮の近くにある伊勢うどんのお店です。

f:id:gedorinku:20161222153906j:plain

 写真のように汁はなく、太くて柔らかい麺に醤油みたいなタレがかかっていました。全体的に少し塩辛いですが、いい感じに麺と混ざると美味しいです。一緒に頼んだうなぎが最高だったので、また食べたいです。

能古うどん

 キャナルシティに映画を見に行く時などに、昼ご飯に迷ったら入る店です。

このお店の麺は、よくある太くて柔らかい麺ではなく、細くてコシがあります。汁は少し薄めで、優しい感じです。他の福岡のうどんと麺が全然違いますが、わりと好きです。

牧のうどん

f:id:gedorinku:20161222154337j:plain

(画像は野菜かき揚げうどんです。)

僕は福岡に住んでいるので、正八郎うどんの次くらいに馴染みがあります。麺はコシがなくて柔らかく、食べるのが遅いと食べてる間にどんどん汁を吸って麺の量が増えていきます。また、麺の硬さ3段階から選べたりします。(僕は中麺しか食べたことないですが・・・)コシのあるうどんもいいですが、僕は柔らかいうどんの方が好きです。

学校の近くにはありませんが、福岡に来たら食べてみてください。

 

まとめ

 うどんは素晴らしい食べ物だと思うので、これからも積極的に食べていきたいです。味のレビューについては、食べた直後に書くべきだと思いました。

 

 

明日23日の記事の担当は、沖縄の美少女、kurokoji(@kuro__koji__)君です。よろしくお願いします。

JOI予選参加記

JOI予選お疲れ様でした。

僕はコンテストなどに出ても振り返り記事を書かないのですが、うぃんじー(@wing3196)さんなどがたくさん記事を書いているので、僕もその流れにのって振り返り記事を書きます。

 

0問目:集合

 とても早く学校に来てしまったので、廊下で昼ご飯を食べるなどして時間を潰します。

これは明らかに教えていない方が悪いのですが、解答の提出方法が怪しい1年生が何人もいたので、1年生に提出方法を教えてました。ギリギリだったのでちゃんと教えることができなくて申し訳ないです。

1問目:電子レンジ

1~3問目はゆっくり落ち着いてコードを書きました。

gist.github.com

2問目:ポイントカード

はずれ印の数要らなじゃん

gist.github.com

3問目:休憩スペース

2つ目のサンプルが間違っていたので少し焦りましたが、そのまま提出しました。

ここまでで競技開始から30分が経過しています。

gist.github.com

4問目:ぬいぐるみの整理

累積和で計算量を落としながらbit DPをして、O(2^mm)。ここでいきなり難易度が上がったのでビビります。

4問目の提出を終えると、1時間20分くらい時間が残っていました。

gist.github.com 

5問目:尾根

いいえ。これもDPかなぁなどと適当なことを考えましたが、分からなかったのでO(H^2W^2)なコードを書いて1ケース目だけを提出しました。競技時間があと残り30分くらいだったので、すべての提出ファイルをダウンロードして提出ミスがないか確認し、6問目を開きました。

6問目:ヘビのJOI君

ダイクストラ法でいい感じにやることは分かりましたが、30分で嘘解法を生やして競技終了です。

 

 

感想

4問目はなんとか実装できましたが、5問目が全く分からなかったので、先に6問目を考えれば良かったかもしれないです。

4問目のような問題は去年の予選の時の自分だったら解けなかったと思うので、年明けから本選までに競プロをやってた分、少しは成長できたかもしれません。ただ、僕は前回の本選からずっと競プロをサボっていた上、周りの人々が精進しているので、このままではまずいと思っています。

あとは、提出ミスをしていないことを祈ります。