PythonでOpenCVやnumpyを使って画像を加工するフィルターいろいろ

python コンピュータ
python

OpenCVには多数の画像フィルターがあります。また、numpyを使うと画像をピクセル単位で加工するフィルターを作成することが出来ます。個人的によく使う画像フィルター類をまとめたいと思います。

ライブラリのインポート

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と比べて動作は遅いです。畳み込み演算の範囲外(外周部)はオリジナル画像のコピーをセットしています。

コメント