粗大メモ置き場

個人用,たまーに来訪者を意識する雑記メモ

Python Opencvを用いた基本行列,基礎行列の推定

今のところただのメモ.気が向いたら説明を書きます.

コードの内容物について

Opencv3 Python3環境上

・特徴点の抽出手法の選択とマッチング,マッチング結果のソートまで
・ビルトイン関数を用いてF行列を推定.エピポーラ線を図示.
・5点法を用いてE行列を復元.F行列もそっち経由で推定

コード


E行列の推定

Geometric Image Transformations — OpenCV 2.4.13.2 documentation
一応流れとしては,画像上の座標をカメラ行列の逆行列焦点距離が1の歪みのない画像へと変換した後に,8点アルゴリズムと同じような線形手法で求解します。
undistortPointsで座標を変換した後にE行列を推定する流れになっています。

その後,カメラ行列を用いてF行列を再現しようとしたのですが正直あんまりうまくいかないなぁといった印象。
どちらがよりまともな計測結果を出しているのかちょっと測りかねます。

3次元の点群の座標を逆算できるのでそれで図示してみればいいだろうか。

#https://stackoverflow.com/questions/33906111/how-do-i-estimate-positions-of-two-cameras-in-opencv
# Normalize for Esential Matrix calaculation
pts1_norm = cv2.undistortPoints(np.expand_dims(pts1, axis=1), cameraMatrix=K, distCoeffs=None)
pts2_norm = cv2.undistortPoints(np.expand_dims(pts2, axis=1), cameraMatrix=K, distCoeffs=None)

E, mask = cv2.findEssentialMat(pts1_norm, pts2_norm, focal=1.0, pp=(0., 0.), method=cv2.RANSAC, prob=0.999, threshold=3.0)
points, R, t, mask = cv2.recoverPose(E, pts1_norm, pts2_norm)

M_r = np.hstack((R, t))
M_l = np.hstack((np.eye(3, 3), np.zeros((3, 1))))

P_l = np.dot(K,  M_l)
P_r = np.dot(K,  M_r)
point_4d_hom = cv2.triangulatePoints(P_l, P_r, np.expand_dims(pts1, axis=1), np.expand_dims(pts2, axis=1))
point_4d = point_4d_hom / np.tile(point_4d_hom[-1, :], (4, 1))
point_4d = point_4d[:3, :].T

Kinv = np.linalg.inv(K)
Kinvt = np.transpose(Kinv)
F = np.multiply(Kinvt,E,Kinv)

カメラ行列と歪み行列

Camera matrix

8.203220199617171602e+02	0.000000000000000000e+00	3.096245711568477077e+02
0.000000000000000000e+00	8.197741669830913906e+02	2.506989838404120974e+02
0.000000000000000000e+00	0.000000000000000000e+00	1.000000000000000000e+00

dist_coeff

-3.122683970392000144e-02
1.165913262734599998e-01
5.941855154279999593e-03
3.277340995399999845e-04
-3.251456801179700151e-01

images

0.jpg
f:id:ossyaritoori:20170625010036j:plain

1.jpg
f:id:ossyaritoori:20170625010113j:plain

結果:F行列推定+エピポーラ線図示

少しパラメータを変えるだけで大きく変わってしまいます.
これ大丈夫かよ.

AKAZE

f:id:ossyaritoori:20170625010520p:plain
歪み補正後
f:id:ossyaritoori:20170625010707p:plain
ロバスト推定→RASAC
f:id:ossyaritoori:20170625010958p:plain

ORB

RANSAC+歪み補正
f:id:ossyaritoori:20170625011105p:plain

ロバスト推定+歪み補正
f:id:ossyaritoori:20170625011153p:plain

改善について

もう少しプログラムの中について調べるべきでしょう.
以下のブログが詳しく,またOctaveのソースもあるのでMatlabでも実装できそう.
qiita.com

反省

そういえば8点アルゴリズム等で基礎行列を求めたけど画像上の点はわりと平面上にあるものが多かった。
こういった環境では線形方程式の自由度が退化して計算結果が不安定になりやすいため,あんまり良くないかもしれないという知見を得た。

そうしたらホモグラフィ行列を元にした3次元再構成をすべきだろうがこれらはどう切り替えればいいのかな?
あるいは切り替えなければ行けないという問題でもないのか。

Python3 "too many values to unpack (expected 2)" in feature detector in OpenCV3

There are many differences between Python2.x and Python3.x.
Also, OpenCV has many changes from opencv2.x to opencv3.x.

Detect ORB feature and matching (Python3,Opencv3)

Following code may be valid in opencv2

kp1,des1 = detector.detect(img1)
kp2,des2 = detector.detect(img2)

But it results in the error:
"too many values to unpack (expected 2)".
In opencv3, you should write as following:

kp1,des1 = detector.detectAndCompute(img1)
kp2,des2 = detector.detectAndCompute(img2)

Refferd(Japanese)
OpenCV3とPython3で特徴点を抽出する(AgastFeature, FAST, GFTT, MSER, AKAZE, BRISK, KAZE, ORB, SimpleBlob, SIFT) - Qiita

The other famous difference between opencv2 and 3 is the place of the package SIFT and SURF.

See
OpenCV 3でPythonからSIFT - danglingfarpointer's memoization


Hope this article will solve your problem.

Raspberry Piの環境をSDカードごとバックアップ

いろいろとセットアップしたラズパイですがSDカードを使っているのでいつデータが飛んでもおかしくないです.
セットアップすればするほど怖いですね.
当然,普通のPCと同じようにバックアップも取れるのですがラズパイはSDまるごとバックアップをとって分身を作ることが可能です.

Ubuntuを用いたバックアップ

まずはUbuntuを用いてバックアップする手順について述べます.
準備物は替えのmicroSDカード(もとのものより容量が大きいOR全く同じが望ましい)
とSDアダプタです.

SDカード内のデータの保存

まずはUbuntuにSDカードを認識させます.
以下のコマンドを打ちましょう.

sudo fdisk -l

以下のようにPCからみれるデバイス一覧を探せます.
容量をチェックしたりSDを抜き差しして新たに追加されたデバイスがどれか特定してください.
f:id:ossyaritoori:20170623202519p:plain
上の画像の場合,「mmcblk0」というのがデバイスの名前になります.

sudo dd if=/dev/mmcblk0 bs=1M | gzip > /home/user名/pi2017June.gz

ddコマンドを用いてデバイスの中身を圧縮形式でuser以下に保存しています.
この操作にはそこそこ時間がかかると思ってください.
私のは32Gあったので30分くらいかかりました.


参考元:
RaspberryPiをバックアップする(コマンド編)

バックアップからの復元

SDアダプタからバックアップ元のmicroSDを抜きcopy先のカードを入れます.
同様の手順でSDを認識させた後に,次のようにバックアップをコピーします.

gzip -dc /home/user名/pi2017June.gz | sudo dd bs=1M of=/dev/mmcblk0

|の前にはバックアップ元,後には認識させたドライバ名を使います.

同様に結構長い時間待てば完了です.やはり欠点は結構操作が重い点です.

参照元
RaspberryPiをバックアップから復元する(コマンド編)

Windowsを用いたバックアップ

いずれ書きます.

Raspberry Piの環境をSDカードごとバックアップ

いろいろとセットアップしたラズパイですがSDカードを使っているのでいつデータが飛んでもおかしくないです.
セットアップすればするほど怖いですね.
当然,普通のPCと同じようにバックアップも取れるのですがラズパイはSDまるごとバックアップをとって分身を作ることが可能です.

Ubuntuを用いたバックアップ

まずはUbuntuを用いてバックアップする手順について述べます.
準備物は替えのmicroSDカード(もとのものより容量が大きいOR全く同じが望ましい)
とSDアダプタです.

SDカード内のデータの保存

まずはUbuntuにSDカードを認識させます.
以下のコマンドを打ちましょう.

sudo fdisk -l

以下のようにPCからみれるデバイス一覧を探せます.
容量をチェックしたりSDを抜き差しして新たに追加されたデバイスがどれか特定してください.
f:id:ossyaritoori:20170623202519p:plain
上の画像の場合,「mmcblk0」というのがデバイスの名前になります.

sudo dd if=/dev/mmcblk0 bs=1M | gzip > /home/user名/pi2017June.gz

ddコマンドを用いてデバイスの中身を圧縮形式でuser以下に保存しています.
この操作にはそこそこ時間がかかると思ってください.
私のは32Gあったので30分くらいかかりました.


参考元:
RaspberryPiをバックアップする(コマンド編)

バックアップからの復元

SDアダプタからバックアップ元のmicroSDを抜きcopy先のカードを入れます.
同様の手順でSDを認識させた後に,次のようにバックアップをコピーします.

gzip -dc /home/user名/pi2017June.gz | sudo dd bs=1M of=/dev/mmcblk0

|の前にはバックアップ元,後には認識させたドライバ名を使います.

同様に結構長い時間待てば完了です.やはり欠点は結構操作が重い点です.

参照元
RaspberryPiをバックアップから復元する(コマンド編)

Windowsを用いたバックアップ

いずれ書きます.

ROSとの競合を避けながらUbuntuでOpenCV環境を再構築

anacondaでいろいろ設定した後にrosを入れるとpythonの環境が複数存在することになって非常に面倒なことになったというお話です.
SSD移行前と手順が違うので以下の過去記事とは完全に別物だと思ってください.
ossyaritoori.hatenablog.com

環境

Ubuntu16.04
Python 3.5.2(Anaconda使用)

Anaconda を用いたOpenCVのインストー

適当に

conda install -c https://conda.binstar.org/menpo opencv3

としてOKです.
Windows Anaconda Python 3.5 への OpenCV 3.1 のインストール - にせねこメモ

私はこの後rosを入れたためトラブルに見舞われました.

エラー状況

インストールの確認のため,

import cv2

とした際に,「ImportError: /opt/ros/kinetic/lib/python2.7/dist-packages/cv2.so: undefined symbol: PyCObject_Type」と出る.

以下のようにrosをいれたことによってpythonのパッケージ参照の優先度が変わったためのようです.
stackoverflow.com

1.Pythonの環境を調べる

import sys
sys.print

これでPathが出てきます.すると出るわ出るわ.
このようにrosのdist-packageが優先になっています.

'', '/opt/ros/kinetic/lib/python2.7/dist-packages', '/home/userx/anaconda3/lib/python35.zip', '/home/userx/anaconda3/lib/python3.5', '/home/userx/anaconda3/lib/python3.5/plat-linux', '/home/userx/anaconda3/lib/python3.5/lib-dynload', '/home/userx/anaconda3/lib/python3.5/site-packages', '/home/userx/anaconda3/lib/python3.5/site-packages/Sphinx-1.4.6-py3.5.egg', '/home/userx/anaconda3/lib/python3.5/site-packages/setuptools-27.2.0-py3.5.egg'

なお,user名はuserxでぼかしています.ご了承を.

これがどういう手順で入っているかは以下の長い解説をご確認を.
Python の module search path ついて調べてみる - Lostman

Where is Python's sys.path initialized from? - Stack Overflow

一時的解決策:sys.pathの順番変更

私のpython環境ではAnacondaを用いた3.5系だったのでパッケージはsite-packagesの直下にあります.
従ってこれを再優先させることでAnacondaで入れたopencvのパッケージを反映することができます.

import sys
sys.path.insert(0,'/home/userx/anaconda3/lib/python3.5/site-packages')

PYTHONPATHを変更する

このように一時的に回避することは可能ですが,Python環境を立てなおした場合にはこの操作は無効になってしまいます.

PYTHONPATH(環境変数みたいなもの)を変更することでこの問題を回避することが可能ですが,これまた再起動すると変更が取り消されてしまいます.

export PYTHONPATH=/home/userx/anaconda3/lib/python3.5/site-packages:$PYTHONPATH

PYTHONPATHを永久的にいじれるようにする

「各自使用するshellを確認するように」という前書きがつきますが,私のように気にしたことのない人のほうが多いでしょう.
以下のような文を~/.bashrcに追加しましょう.(user名の置換を忘れずに)

export PYTHONPATH="/home/userx/anaconda3/lib/python3.5/site-packages:$PYTHONPATH"

他の記述の影響を受けないように最後行に書くのが良いと思います.

その後この反映をすぐに実行するには

source ~/.bashrc

として実行してください.

ja.stackoverflow.com

テストコード置き場

顔認識(静止画・動画・マルチスレッド)


キャリブレーション

imagesという名前のフォルダ内にjpgで撮影画像を入れておくと勝手にキャリブレーションを行ってくれるように書きました.
rms誤差とカメラ行列K,歪み行列をcsv形式で同時に保存しています.

なおキャリブレーションに用いたチェッカーボードの画像がなかなか手に入らないのでここにおいておきますw
http://opencv.jp/sample/pics/chesspattern_7x10.pdf
なお,縦横比がA4と少し違うので原寸で印刷することを忘れずに!

「インターネットなし,セキュリティ保護あり」となりネットに繋がらない

上記のメッセージが出たときは基本再起動安定ですが,僕に起こった事件ではもっと面倒な事を要求されました。

多分,以下のと似たような事例なんだと思います。
windows10で最近ネットがつながらなくなったら、まず放電を試すべき - パソコンりかばり堂本舗

とにかく,放電せよとのことです。電池を抜いて10分ほど放置すれば治りました。
どうもPC本体が不調なのかな?
よくわかりませんがとにかくこういうこともあるということで。

Texで行列を楽に書く方法

Latexでの行列の書き方。

Latexで行列を書くのは面倒です。

よく使う書き方としては大体以下の2つが挙げられるでしょう,

\begin{pmatrix}
a & b \\
c & d 
\end{pmatrix}

または,

\left( \begin{matrix}
a & b \\
c & d 
\end{matrix} \right)

出力はマージンに違いこそあれこうなりますね。
f:id:ossyaritoori:20170610134858p:plain

でも正直これ,すっごく打つのが面倒くさいです。
そもそもbeginって打ちたくないんだよなぁ。

行列を簡単に書くためのマクロ

そこでマクロを組みます。

以下のような宣言を行えば,

\newcommand{\pmat}[1]{\begin{pmatrix} #1 \end{pmatrix}}%行列簡略化
\newcommand{\mat}[1]{\left( \begin{matrix} #1 \end{matrix} \right)}%行列簡略化

先程の2つは次のように書けるようになります。スッキリするし何より可読性が上がります。

\pmat{a & b \\ c & d }

\mat{a & b \\ c & d}

Shift押しながら入力する「{,},(,)」の入力が減ったので大いにストレスが減ります。オススメです。

一応マクロの解説

マクロの順番としては受け入れ関数名,引数の数,処理内容となっています。

\newcommand{受け入れ関数名}[引数の数]{処理内容,ただしn番目の引数を#nと表す}

ちょっと書きなれないけど慣れれば素早くマクロを組めるようになるでしょう。
(ただしマクロが多すぎるコードは可読性が低くなるので注意!)