opencvを使いcanny法で画像をエッジ変換する

■サンプルコード

■実行結果
canny test

opencvを使いハフ変換で画像から円を探す(HoughCircles)

HoughCircles(image, circles, method, dp, minDist, param1, param2, minRadius, maxRadius)

ハフ変換を用いて画像内から円を検出する

項目 内容
image 8ビット,シングルチャンネル,グレースケールの入力画像
circles 検出された円を出力するベクトル
method 現在のところCV_HOUGH_GRADIENT メソッドのみが実装
dp 画像分解能に対する投票分解能の比率の逆数
minDist 検出される円の中心同士の最小距離.このパラメータが小さすぎると,正しい円の周辺に別の円が複数誤って検出される
param1 手法依存の 1 番目のパラメータ. CV_HOUGH_GRADIENT の場合は, Canny() エッジ検出器に渡される2つの閾値の内,大きい方の閾値を表す
param2 手法依存の 2 番目のパラメータ. CV_HOUGH_GRADIENT の場合は,円の中心を検出する際の投票数の閾値を表す.これが小さくなるほど,より多くの誤検出が起こる可能性がある
minRadius 円の半径の最小値
maxRadius 円の半径の最大値

■入力画像
houghcircles test

■処理コード

■結果
houghcircles test

opencvを使い確率的ハフ変換で画像から直線を探す

ハフ変換は与えられたパラメータから全条件を計算し直線を求めるのに対し、確率的ハフ変換はある程度の当たりをつけて計算し、負荷を軽くする。

HoughLinesP(image, lines, double rho, double theta, int threshold, double minLineLength=0, double maxLineGap=0)

■入力画像
houghline test

■処理コード

■結果
houghline test

opencvを使いハフ変換で画像から直線を探す

ハフ変換は画像の中にある直線形状や円形状を検出する際に用いられる手法の一つ。opencvではHoughLinesという関数が用意されており、これを使うことで検出が容易となる(計算付加は指定するパラメータの精度により異なる)。

HoughLines(image, lines, rho, theta, threshold, srn, stn)
項目 内容
image 8ビット,シングルチャンネルの2値入力画像.この画像は関数により書き換えられる可能性がある
lines 検出された直線が出力されるベクトル.各直線は,2要素のベクトル (rho, theta) で表現される. rho は原点(画像の左上コーナー)からの距離, theta はラジアン単位で表される直線の回転角度
rho ピクセル単位で表される投票空間の距離分解能
theta ラジアン単位で表される投票空間の角度分解能
threshold 投票の閾値パラメータ.十分な票を得た直線のみが出力される
srn マルチスケールハフ変換において,距離分解能 rho の除数となる値.投票空間の粗い距離分解能は rho となり,細かい分解能は rho/srn となる.もし srn=0 かつ stn=0 の場合は,古典的ハフ変換が利用される.そうでない場合は,両方のパラメータが正値である必要がある
stn マルチスケールハフ変換において,角度分解能 theta の除数となる値

■入力画像
houghline test

■処理コード

■結果
houghline test

opencvの機能を使いモルフォロジー演算を行う

画像からのノイズ除去、テクスチャ解析等に使用される演算手法。背景の画素と隣接する物体の画素の関係を膨張(dilate)、収縮(erosion)させることで画像の2値化、グレースケール化を行うことができる。

openCVではmorphologyExのメソッドによりさらに以下の処理が可能。
オープニング処理  収縮した結果に対して同じ回数だけ膨張する
クロージング処理  膨張した結果に対して同じ回数だけ収縮する
グラジエント処理   膨張した結果から収縮した結果を差し引く
トップハット処理  元画像からオープニングした画像を差し引く
ブラックハット処理 クロージングした画像から元画像を差し引く

■入力画像
morphology input data

■処理コード

■処理結果
morphology results

画像に対するフーリエ変換の物理的意味を考える

対象 説明
信号 縦軸を振幅、横軸を時間とした波形情報を周波数の分布に変換する
画像 縦軸を1ピクセルあたりの画素強度、横軸を座標として、ピクセル間の強度値変化を周波数分布に変換する

画像に対するフーリエ変換のピクセルあたりの画素強度の例として、1×7サイズのグレースケール画像を考える。例えば下記のようなもの(ここでは視認性のため、拡大した画像で表示)。

2dfft_row_column

画素強度値は明るいほど値が大きい。つまりグレースケールの255階調で考えれば、白い箇所は255、黒い箇所は0の値となる。先ほどの画像にピクセル毎に強度値を重ねて表示すると下記のような値を持つ。

2dfft_row_column

上記画像の強度値を、縦軸を1ピクセルあたりの画素強度、横軸を座標として表しなおしたグラフが下記。画像に対するフーリエ変換はこのグラフに対して行っていることになる
pixel peak

ただし通常画像はもっと大きなサイズであり、1ピクセル高ということはない。そのため、実際には各ピクセル行に対してフーリエ変換を行う。各行へのフーリエ変換の実施後はデータを転置し、転置後のデータに対して再度各行に対してフーリエ変換を実施する。その後再度転置を行いデータの向きを元に戻す作業を行う。これで画像に対する2次元フーリエ変換となる。
2dfft_row_column

ここまでの内容をpythonコードにしたものが下記。

2dfft_row_column

numpyとopenCVを使った画像のフーリエ変換と逆変換

openCVを使い画像読み込み、fftで周波数データに変換。その後逆変換で元の画像に戻すテスト。

入力に使用する画像は↓。サイズは360×240。
input data to fft

まず画像入力、グレースケールで取り込む。

実行すると元の画像がグレースケールで表示される。
imreadは引数2つ、1つ目は読み込みファイル、2つ目は読み込みオプションで以下3つ(1,0,-1でも指定可)。

  cv2.IMREAD_COLOR (or 1)
  cv2.IMREAD_GRAYSCALE (or 0)
  cv2.IMREAD_UNCHANGED (or -1)

続けてFFT実施

np.fft.fft2()は2次元FFT。
実行結果が下記。入力が360×240画像だったので、360×240のnumpy arrayで返ってくる。

変換結果をパワースペクトルで確認してみる。確認に使用したコードが下記。

実行結果下記
input data to fft

最後に逆変換で元の画像に戻すコード。注意として変換後の結果には複素数成分が含まれているので、実部を取り出す処理が必要。またグレースケールで表示するために0-255階調への値調整が必要になる。

実行結果が下記グレースケールでもとの画像に戻ってきた。
results fft and inv fft

Read images using openCV, convert to frequency data with fft. And then back to the original image with reverse transformation.
Code 1 is reading image by gray scale.
Code 2 is 2D fft by numpy. Frequency distribution is returned.
Code 3 is checking Power spectrum.
Code 4 is invers Fourie by numpy.

pythonのthreadingを使いクーロン力の並列計算をするテスト

以前行った、multiprocessingでのクーロン力並列計算に引き続き、threadingを使ったクーロン力の並列計算をテストする。計算条件はmultiprocessingの時と同じくcore数を4、計算粒子数を15^3個とした。

結果、計算時間は14.36[sec]。multiprocessingでの計算は2.09[sec]であったため、大分時間がかかるというかシングルスレッドで計算していた時より時間がかかっている。threadingでは各threadがメモリを共有するために必要な情報を取得するためメモリアクセスする際に、排他ロック(GIL)が起きているのかな、と考えられる。試しにthread数を1にして実行してみると処理時間は6.92[sec]。thread化しない方が高速であった。

■結果 [Results summary]

code type 時間[sec]
threading (4threads) 14.36 <-(new!)
threading (1thread) 6.92 <-(new!)
multiprocessing 2.09
itertools使用 (no1) 8.18
range記述 (no2) 7.93
xrange記述 (no3) 7.89
ループ内周でnumpy使用 (no4) 78.46

■使用したコードは下記(use 4 threads)

Following previous parallel computation of Coulomb force in multiprocessing, we test parallel computation of Coulomb force using threading. The same condition as before the multiprocessing calculation condition, the core number was set to 4 and the number of calculated particles was set to 15 ^ 3.

As a result, the calculation time is 14.36 [sec]. The computation with multiprocessing was 2.09 [sec], so it took a long time or it took more time than when computing with single thread. In threading, it is considered that an exclusive lock (GIL) is occurring when memory access is performed in order to acquire necessary information for each thread to share memory. If we try to run with thread number 1, the processing time is 6.92 [sec]. It was faster to not thread.

マルチスレッドのテスト

スレッドを発行して並列化するテスト。スレッドの開始はstart(),終了待ちはjoin()で行う。すべてのスレッドの終了をチェックするためには、現在発行中の全スレッドをリストアップするenumerate()を使う。ただしこのリストの中には、メインスレッドも含まれているので、メインスレッドは抜く必要がある。メインスレッドはcurrentThread()であらわせるので、これをremoveで取り除く。取り除いた結果に対して、join()で終了待ちし、全スレッドが終了したら終了メッセージを出す。各スレッドからの返り値はQueueを使って貯めることができる。貯めたいqueueを引数に渡してやることで、スレッド終了後に全スレッドの結果を読み出すことができる。

■実行結果
thread = 0 rand = 1.97370804812
thread = 1 rand = 3.45525477664
thread = 2 rand = 0.651252139145
thread = 3 rand = 3.96551177159
thread = 4 rand = 3.57845628232
thread = 5 rand = 1.81758678574
thread = 6 rand = 2.31490107118
thread = 7 rand = 1.21471678276
end thread = 2
end thread = 7
end thread = 5
end thread = 0
end thread = 6
end thread = 1
end thread = 4
end thread = 3
[0.6512521391445797, 1.2147167827645151, 1.817586785739616, 1.9737080481200742, 2.3149010711817626, 3.4552547766386787, 3.5784562823201704, 3.9655117715879653]
end

A test that issues threads and parallelizes them. The start of the thread is done with start (), and the wait for completion is done with join (). To check the termination of all threads, use enumerate () which lists all the threads that are currently issuing. However, since the main thread is also included in this list, it is necessary to withdraw the main thread. The main thread can be set with currentThread (), so remove it with remove. Wait for join () to finish removing, and issue a termination message when all threads are finished. The return value from each thread can be stored using Queue. By passing the queue you want to save as an argument, you can read the results of all threads after the thread ends.