ガウシアンフィルタ
作業の流れ
ハフ変換を行う前にCanny法というものを使ってエッジ検出を行います。 Canny法ではまずガウシアンフィルタによるぼかしの処理を行います。
よってPythonの練習もかねて、まずガウシアンフィルタを実装しようと思います。
ガウシアンフィルタを使う例
ガウシアンフィルタは趣味のお絵描きでもよく使用している便利な処理です。 以下にガウシアンフィルタがイラスト制作に使われる例を示します。 (プログラム書く前に絵の制作で時間を溶かしたのは内緒...)
このように、イラストの背景にガウスぼかしをかけることによって主役の人物が見やすくなります。 この処理はお絵かきソフトClipStudioで行いました。
このガウスぼかしに使用するガウシアンフィルタを実装していきます。
ガウシアンフィルタの原理
ガウシアンフィルタではガウス分布というものを利用して、注目画素からの距離に応じて近傍の画素値に重みをかける処理を行っています。以下にガウス分布の式を載せます。
ガウス分布は確率統計とかでよく出てくる正規分布と同じものみたいです。偏差値の計算など、色々なところで使われるみたいです。 このガウス分布によって注目画素の周りの画素の画素値に重みを付けることでぼかしていきます。
プログラム
実際にガウシアンフィルタを行うプログラムです。 グレースケール化は無くても良いのですが勉強の過程で書いてみて、今後も必要なので載せました。
import cv2 import numpy as np #グレースケール化 def BGR2GRAY(img): b = img[:,:,0].copy() g = img[:,:,1].copy() r = img[:,:,2].copy() print(b) out = 0.2126*r + 0.7152*g + 0.0722*b #整数に変換 out = out.astype(np.uint8) return out #ガウシアンフィルタ def gaussian_filter(img,k_range=7,sigma=1.3): #入力画像がカラーかグレー化を判定し、グレーなら要素を増やす if len(img.shape) == 3: H,W,C = img.shape else: img = np.expand_dims(img,axis=-1) H,W,C = img.shape #//は切り捨て除算 pad = k_range//2 #隅の画素でも重み付けができるように0パディング out = np.zeros((H + pad *2,W + pad * 2,C),dtype=np.float) #入力画像を0パディング付きで複製 out[pad: pad + H,pad: pad + W] = img.copy().astype(np.float) #カーネルの準備 K = np.zeros((k_range,k_range),dtype=np.float) for x in range(-pad,-pad + k_range): for y in range(-pad, -pad + k_range): #ここで肝のガウス分布の式が登場 K[y + pad,x + pad] = np.exp(-(x ** 2 + y ** 2)/(2 * (sigma ** 2))) K /= (2*np.pi * sigma * sigma) #最後にカーネルの合計で割る K /= K.sum() tmp = out.copy() for y in range(H): for x in range(W): for c in range(C): out[pad + y,pad + x,c] = np.sum(K * tmp[y: y + k_range,x:x + k_range,c]) #0から255の範囲に収める out = np.clip(out,0,255) out = out[pad: pad + H,pad:pad + W].astype(np.uint8) return out img = cv2.imread("hough.png").astype(np.float) out = gaussian_filter(img) cv2.imshow("result",out) cv2.waitKey(0)
gaussian_filter内の画像はこのような感じになっているはずです。
このサイトのコードをガッツリ参考にしました github.com
結果はこんな感じです。
このガウシアンフィルタ、実はOpenCVのメソッドを使うと10行で実装できてしまいます。
import cv2 import numpy as np from matplotlib import pyplot as plt img = cv2.imread('hough.png') #kernel = np.ones((5,5),np.float32)/25 out = cv2.GaussianBlur(img,(7,7),1.3) cv2.imshow("result",out) cv2.waitKey(0)
次はこのガウシアンフィルタを使ってCanny法を実装しようと思います。
ハフ変換を手軽に行うウェブアプリを作りたい
大学の講義でハフ変換という技術を学び、画像処理100本ノックQ44_Q46でハフ変換のプログラムを学びました。
この時、このハフ変換による直線検出は絵を描く際のパース取りに使えるのではないか閃き、ダウンロードやインストールなどの煩わしい手順は無く、webで簡単にできるハフ変換アプリが作りたいと考えました。
現在の進捗としては、取り合えずPythonが使える環境を整え、簡単なPythonの書き方を勉強しました。(今まで画像処理はC++で行っていた)
現状、100本ノックのハフ変換プログラムを完全に理解したわけでは無いため、次はハフ変換のプログラムを自力で書けるようになろうと思います。 OpenCVにはハフ変換を行う関数が付いているみたいなので、それを使ってしまう誘惑に負けないように、頑張ろうと思います。
OpenPose、gitの導入とブログ散策
今日はOpenPoseにより取得した2次元の骨格データを3次元に推定する技術について調べました。
OpenPoseは既に私用のPCでデモを動かしており、初めて動かした際にはかなり感動しました。 この技術があれば手軽なモーションキャプチャなんて簡単だと思ったのですが、そう上手くはいかないみたいです...。
OpenPoseでは画像の関節の位置を取得できるのですが、それはあくまで2次元であり、そのデータを3次元の姿勢に推定しなければモーションキャプチャとして3Dモデルを動かすことはできません。
姿勢推定のコードはGitHubにいくつかあるようで、今日は主に以下のページを読んでいました。
またgitをインストール、コマンド入力によりGiuHubのファイルをDLできるようになりました。(今更...)
今までは学校からの課題に取り組むだけでしたが、これからは色々な方のブログやGitHubのコードを読み、自分もアウトプットしていきたいと思います。
C++でVectorに触れた
画像処理100本ノック、問32番へ取り組んだ際に問題が発生したので記録します。 github.com
double型の複素数を要素に持つ二次元配列を使用したらVisual Studioに怒られました。 スタック領域では16KBまでしか使えないとかなんとか...
そこで友人の力を借りてVector型について学び、無事解決できました。
怒られたコード
〜 struct fourier_str { std::complex<double> coef[height][width]; }; 〜
修正したコード
〜 struct fourier_str { std::vector<std::vector<std::complex<double> > > coef; fourier_str() : coef(height,std:: vector<std::complex<double> >(width)) {} }; 〜
[5月18日追記]
二次元配列を使用して怒られた際には、作成した構造体を引数に持つ関数を幾つか作成するプログラムでしたが、これをすべてmain関数にまとめてしまうと怒られなくなりました...。 謎は深まる...。