[学習メモ]OpenCVを用いた平滑化,二値化, 輪郭の抽出


画像の平滑化

いくつかの平滑化の仕方を紹介。

平均

カーネルの範囲内にある全画素の画素値の平均をとる。

  • img:入力画像
  • ax:カーネルの横幅
  • ay:カーネルの縦幅
blur.py
blur=cv2.blur(img,(ax,ay))

ガウシアンフィルタ

ホワイトノイズに適している。
単に平均をとるのではなくガウシアンフィルタは注目画素との距離に応じて重みを変えることができる。

  • img:入力画像
  • ax:カーネルの横幅(奇数)
  • ay:カーネルの縦幅(奇数)
  • sigma_x:横方向の標準偏差。0にした場合、カーネルサイズから自動的に計算される。
gauusian.py
gau=cv2.GaussianBlur(img,(ax,ay),sigma_x)

中央値フィルタ

ごま塩ノイズに適している。
カーネル内の全画素の中央値を計算する。

  • img:入力画像
  • k:カーネルのサイズ(奇数)
median.py
 median=cv2.medianBlur(img,k)

バイラテラルフィルタ

エッジを残したまま画像をぼかすことができる。
処理速度が遅くなるという欠点がある。
詳しくはpython+OpenCVでエッジを保存した平滑化(BilateralFilter, NLMeansFilter)
画像を平滑化する その1 - OpenCV for Android

  • img:入力画像
  • d:注目画素をぼかすために使われる領域。大きくなるとぼかしが強くなる。
  • sigmaColor:色空間の標準偏差。これが大きいと、近くにある色的により遠くのピクセルが混ぜ合わせられる。
  • sigmaSpace:距離空間の標準偏差。これが大きいと、より遠くのピクセル同士が影響しあいます。 dがゼロ以下の場合のみ計算に利用される。
bilateral.py
 bilate=cv2.bilateralFilter(img,d,sigmaColor,sigmaSpace)

画像の二値化

  • img:入力画像(グレイスケール)
  • thresh:しきい値
  • maxval:しきい値以上の値を持つ値に対して割り当てる値を指定
  • type:THRESH_BINARY_INVの場合しきい値よりも大きな値であれば0、それ以外はmaxvalの値にする。 typeの他の種類はOpenCV - 画像の2値化について参照
threshold.py
ret, th=cv2.threshold(img,thresh,maxval,type)
  • ret:threshと同じ値
  • th:二値化した画像

輪郭の抽出

輪郭の取得

  • image:入力画像(二値画像のほうが精度がいい)
  • mode:抽出モード
  • method:近似手法

第2引数は以下の引数で指定できる。

定数 意味
cv2.RETR_LIST 単純に輪郭を検出
cv2.RETR_EXTRNAL 最も外側の輪郭を検出
cv2.RETR_CCOMP 階層を考慮し2レベルの輪郭を検出
cv2.RETR_TREE 全ての輪郭を検出し階層構造を保持

第3引数は以下の引数で指定できる。

定数 意味
cv2.CHAIN_APPROX_NONE 輪郭上のすべての点を保持する
cv2.CHAIN_APPROX_SIMPLE 冗長な点情報を削除して返す
contours.py
imges, contours, hierarchy=cv2.findContours(image,mode,method)
  • images:輪郭画像
  • contours:輪郭
  • hierarchy:輪郭の階層情報

輪郭の描写

  • img:入力画像
  • contours:listとして保存されている輪郭
  • ind:描画したい輪郭のインデックス(第2引数で与えた輪郭のlistから一つの輪郭だけを描画する時に描画したい輪郭の指定に使う.全輪郭を描画する時はー1を指定する)
  • (r,g,b):輪郭を描画する色
  • num:輪郭を描画する線の太さ
contours.py
img = cv2.drawContours(img, contours, ind, (r,g,b),num)

まとめ

まとめるとこんな感じになる。

sum.py
# -*- coding: utf-8 -*-

import cv2
import matplotlib.pyplot as plt

# 画像を読み込んでリサイズ --- (*1)
img = cv2.imread("flower.jpg")
img = cv2.resize(img, (300, 169))

# 色空間を二値化 --- (*2)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (7, 7), 0) 
im2 = cv2.threshold(gray, 140, 240, cv2.THRESH_BINARY_INV)[1]


# 輪郭を抽出 --- (*4)
imges, contours, hierarchy = cv2.findContours(im2, 
        cv2.RETR_LIST, #単純に輪郭を検出
        cv2.CHAIN_APPROX_SIMPLE) #冗長な点情報を削除して返す

#全ての輪郭を赤で表示
img_co = cv2.drawContours(img, contours, -1, (225,0,0), 3)
plt.imshow(img_co)

花の画像(左)に対してすべての輪郭を赤で表示した(右)。

すぐに使える!業務で実践できる!Pythonによる AI・機械学習・深層学習アプリのつくり方

画像の平滑化

輪郭: 初めの一歩