OpenCVには多数の画像フィルターがあります。また、numpyを使うと画像をピクセル単位で加工するフィルターを作成することが出来ます。個人的によく使う画像フィルター類をまとめたいと思います。
- ライブラリのインポート
- 画像ファイルの読み込み
- 画像ファイルの書き込み
- 画像ファイルの書き込み
- 画像の表示
- 2値化
- 大須の2値化
- グレースケール化
- ぼかし処理
- ガウシアンフィルター
- メディアンフィルター
- バイラテラルフィルター
- ノンローカルミーンフィルター(グレースケール)
- アンシャープマスキングフィルター
- ガンマ補正
- ソーベルフィルター
- 指定面積以下の物体を塗りつぶし
- リサイズ
- 画像の重ね合わせ
- 画像の減算
- ネガポジ反転
- 畳み込み演算による平滑化(ぼかし処理)
- 任意の解像度のグレスケール画像を生成
- 任意の解像度のカラー画像えを生成
- 座標を指定してピクセルにアクセス
- 座標を指定して特定のチャンネルにアクセス
- 特定のチャンネルを塗りつぶし
- 範囲指定で塗りつぶし
- numpy.where()による2値化
- 幅、高さ、チャンネル数を取得
- LUTによる減色
- グレースケール同士の2つの画像の違いを抽出
- そのた
ライブラリのインポート
import cv2
import numpy as np
import os
osは画像加工には直接関係ないですが、画像ファイルの読み書きのパスの生成やファイルの有無の確認、ディレクトリの作成用
画像ファイルの読み込み
カラー読み込み
img = cv2.imread("F:/tmp/hoge.jpg",1)
グレースケールで読み込み
img = cv2.imread("F:/tmp/hoge.jpg",0)
パスに日本語?含むファイルは読み込めない。
画像ファイルの書き込み
cv2.imwrite("F:/tmp/hoge.jpg", img)
画像ファイルの書き込み
cv2.imwrite("F:/tmp/hoge.jpg", img)
画像の表示
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
CLI環境でウィンドウで画像を表示します。
任意のキーを押されるまで待ち、キーが押されるとウィンドウを破棄します。
2値化
result = np.where(gray < 128, np.uint8(0), np.uint8(255))
numpyのwhereを使って128をしきい値に0か255に分類する単純な方法
大須の2値化
ret,result = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU)
適切なしきい値が自動的に設定されます。引数の閾値(0)は使われない模様。
グレースケール化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
imreadでカラーとして読み込んだ画像(BGR)をグレースケールへ変換
RGB[A] to Gray:Y←0.299⋅R+0.587⋅G+0.114⋅B
緑成分強め
ぼかし処理
result = cv2.blur(img, (3,3))
カーネルサイズは奇数
ガウシアンフィルター
result = cv2.GaussianBlur(img, (3,3), 0)
メディアンフィルター
result = cv2.medianBlur(gray, 3)
バイラテラルフィルター
result = cv2.bilateralFilter(gray, 3, sigmaColor=999, sigmaSpace=20)
ノンローカルミーンフィルター(グレースケール)
result = cv2.fastNlMeansDenoising(gray, h=15)
アンシャープマスキングフィルター
def unsharp(src, k=1.5):
kernel = np.array( [[-k/9.0, -k/9.0, -k/9.0],
[-k/9.0, 1.0+(8.0*k)/9.0, -k/9.0],
[-k/9.0, -k/9.0, -k/9.0]])
dst = cv2.filter2D(src, -1, kernel)
return dst
ガンマ補正
gamma = 0.9
x = np.arange(256)
y = (x / 255) ** gamma * 255
result = np.uint8(cv2.LUT(gray, y))
ソーベルフィルター
sobel_x = cv2.Sobel(gray, cv2.CV_32F, 1, 0, ksize=3)
sobel_y = cv2.Sobel(gray, cv2.CV_32F, 0, 1, ksize=3)
sobel_x = cv2.convertScaleAbs(sobel_x)
sobel_y = cv2.convertScaleAbs(sobel_y)
result = cv2.addWeighted(sobel_x, 0.5, sobel_y, 0.5, 0)
指定面積以下の物体を塗りつぶし
def fc(gray, am=9):
th=cv2.adaptiveThreshold(gray, 255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY,11,2)
contours,hierarchy = cv2.findContours(th, cv2.RETR_EXTERNAL | cv2.RETR_TREE , cv2.CHAIN_APPROX_NONE)
new_contours=[]
for c in contours:
s=abs(cv2.contourArea(c))
if s <= am:
new_contours.append(c)
cv2.drawContours(gray, new_contours, -1, 255, -1)
return gray
リサイズ
scale=4.0
result = cv2.resize(img, None, fx=scale, fy=scale, interpolation=cv2.INTER_LINEAR)
interpolation(補完方法)
cv2.INTER_NEAREST
cv2.INTER_LINEAR
cv2.INTER_AREA
cv2.INTER_CUBIC
cv2.INTER_LANCZOS4
画像の重ね合わせ
result = cv2.addWeighted(img1, 0.5, img2, 0.5, 0.0)
画像の減算
result = cv2.subtract(img1, img2)
ネガポジ反転
result = cv2.bitwise_not(img)
畳み込み演算による平滑化(ぼかし処理)
def avgBlur(src, ksize=3):
d = int((ksize-1)/2)
dst = src.copy()
(h, w) = src.shape[:2]
for y in range(d, h-d):
for x in range(d, w-d):
a = np.ravel(src[y-d:y+d+1, x-d:x+d+1])
dst[y][x] = np.mean(a)
return dst
OpenCVのfilter2Dメソッドと同じような動作をするフィルターをnumpyで記述しています。
サンプルでは平均をとるblurなのでnp.meanを使っていますが、カーネルを引数に取るようにすると、よりfilter2Dのような形になります。filter2dと比べて動作は遅いです。畳み込み演算の範囲外(外周部)はオリジナル画像のコピーをセットしています。
任意の解像度のグレスケール画像を生成
width = 640
height = 480
img=np.zeros((height, width), np.uint8)
任意の解像度のカラー画像えを生成
width = 640
height = 480
channel = 3
img=np.zeros((height, width, channel), np.uint8)
座標を指定してピクセルにアクセス
カラー
x = 1
y = 0
img[y][x] = [255,255,255]
x = 1
y = 0
img[y][x] = 255
座標を指定して特定のチャンネルにアクセス
x = 0
y = 0
img[y,x,0] = 255
座標x=0:y=0の0(B…青)番目のチャンネルに255を代入
特定のチャンネルを塗りつぶし
img[:,:,2] = 255
範囲指定で塗りつぶし
img[1:3,1:3] = [0, 255, 0]
x座標1~2y座標1~2の範囲を緑色で塗りつぶす。
numpy.where()による2値化
th = np.where(gray < 128, np.uint8(0), np.uint8(255)
grayの要素全てに対し128より小さい場合は0(黒)それ以外は255(白)で生成した画像配列をthに返す。
幅、高さ、チャンネル数を取得
h, w, channel= img.shape
LUTによる減色
def gensyoku(img, k=8):
LUT = []
width = 256/k # 32.0
center = 256/k/2 # 16.0
for i in range(k): # i:0~7
value = center + (width*i) # 置き換える値を算出
ave_list = [value]*int(width) # 同じ色の幅ぶん要素の配列
LUT = LUT+ave_list # 配列に追加
LUTN = np.array(LUT, dtype=np.uint8) # 配列をndarrayに変換
return cv2.LUT(img, LUTN)
グレースケール同士の2つの画像の違いを抽出
diff = np.where(img_a != img_b, np.uint8(255), np.uint8(0))
img_aとimg_bが同じ部分は黒、異なる部分が白の2値画像が出来上がる。
そのた
import cv2
import numpy as np
import os
# 減色
def gensyoku(img, k=8):
LUT = []
width = 256/k # 32.0
center = 256/k/2 # 16.0
for i in range(k): # i:0~7
value = center + (width*i) # 置き換える値を算出
ave_list = [value]*int(width) # 同じ色の幅ぶん要素の配列
LUT = LUT+ave_list # 配列に追加
LUTN = np.array(LUT, dtype=np.uint8) # 配列をndarrayに変換
return cv2.LUT(img, LUTN)
# ガンマ補正
def gamma(img, g=0.9):
x = np.arange(256)
y = (x / 255) ** g * 255
return np.uint8(cv2.LUT(img, y))
# 十字
def cross(src):
kernel = np.array( [[0.0/8.0, 1.0/8.0, 0.0/8.0],
[1.0/8.0, 4.0/8.0, 1.0/8.0],
[0.0/8.0, 1.0/8.0, 0.0/8.0]])
dst = cv2.filter2D(src, -1, kernel)
return dst
def filter(src):
dst = src.copy()
# ぼかし
for i in range(3):
dst = cross(dst)
#dst = cv2.GaussianBlur(dst, (3,3), 0)
# ガンマ補正
dst = gamma(dst, 1.1)
# ノンローカルミーン
dst = cv2.fastNlMeansDenoising(dst, h=5)
return dst
if __name__ == '__main__':
input_path = 'input/005.jpg'
output_path = 'outdir/005.png'
img = cv2.imread(input_path,0)
dst = filter(img)
cv2.imwrite(output_path, dst)
コメント