最近画像処理 100 本ノックというのを始めました。
https://qiita.com/yoyoyo_/items/2ef53f47f87dcf5d1e14
最近画像処理にちょっと興味があって numpy を上手に使いたいなぁ〜と思っていたので非常にありがたい問題集なのですが, Q.9. ガウシアンフィルタ, Q.10. メディアンフィルタ の解答例に不満があった(python で for 文を使いたくない!)のでなるべく numpy を使う処理を書いて速度を比較しました。
今回書いたコード:
def gaussian_filter(_img, filter_matrix):
# assume that fY and fX is odd number
(fY, fX) = filter_matrix.shape
mY = (fY - 1) // 2
mX = (fX - 1) // 2
(Y, X, C) = _img.shape
img = np.zeros((Y + mY*2, X + mX*2, C))
img[mY:Y+mY, mX:X+mX, :] = _img
out_img = np.zeros_like(_img, np.float32)
for dy in range (fY):
for dx in range(fX):
out_img += filter_matrix[dy][dx] * img[dy:Y+dy, dx:X+dx, :]
return out_img.astype(np.uint8)
画像の y, x ではなく filter_matrix
の y, x を for で回すことで画像における足し算は numpy の for を使えるようにしています。
速度比較
gaussian_filter を 100 回呼び出して何秒かかるかを比較しました。time
コマンドを使ってるので画像読み込み 1 回分の時間も含まれてますが大勢に影響はないと思います。
手法 | 時間 |
---|---|
今回のコード | 0.72 |
模範解答 | 50.60 |
圧倒的じゃないか我が軍は〜〜〜
Q10. メディアンフィルタについても, H * W * (filter_size) の画像(?)を作ってからその画像に対して np.median(axis=2) をやれば高速化できるんじゃないか~~と思います。~~できました。
def median_filter(_img, filter_size):
# assume that filter_size is odd
half_size = (filter_size - 1) // 2
(Y, X, C) = _img.shape
img = np.zeros((Y + half_size*2, X + half_size*2, C))
img[half_size:Y+half_size, half_size:X+half_size, :] = _img
out_img = np.zeros_like(_img)
for c in range(C):
big_ch_img = np.zeros((Y, X, filter_size**2))
for fy in range(filter_size):
for fx in range(filter_size):
ch = fy * filter_size + fx
big_ch_img[:,:,ch] = img[fy:fy+Y, fx:fx+X,c]
out_img[:,:,c] = np.median(big_ch_img, axis=2)
return out_img
計測時間は 1.71 秒 vs 302.98 秒でした。
ところで Pooling については for 文を使わない方法を思いついてないので誰か知ってたら教えて下さい。