ソースに絡まるエスカルゴ

貧弱プログラマの外部記憶装置です。

【python/OpenCV】カメラの歪み補正を行う方法

 カメラのレンズの種類によっては画像自体に歪みが発生する場合があります。(広角レンズなど)

 そのカメラの歪みをpythonOpenCVを使って補正する方法を説明していきます。

 基本的には参考資料にあるページ様のソースコードそのままなので、詳しい内容はそちらを参照してください。

 では始めます。


1:チェスボードの準備
 カメラの歪み補正にはチェスボードを用います。ネットで画像検索すれば色々見つかりますが、自分が適当に作成したものがあるので面倒な方は以下のpdfファイルをダウンロードして印刷して使ってください。

 また、あとで使用するのでマス目の1辺の長さも定規で計測しておくとよいです。


2:補正したいカメラを使ってチェスボードを撮影する
 チェスボードの準備ができたら、そのチェスボードを机なりに置いた状態で補正したいカメラを使って様々角度からチェスボードを撮影します。

 撮影する時は以前記事で紹介した画像キャプチャ用のソースコードを使うと楽かと思います。

 以下が実際に撮影した写真の例です。このように様々な角度からチェスボードを撮影します。
f:id:rikoubou:20190326133857p:plain
f:id:rikoubou:20190326140115p:plain
f:id:rikoubou:20190326135818p:plain

 歪みを補正する精度を高めるためにはチェスボードが写っている画像が20枚ほど必要になるので、頑張って撮影してください。


3:補正用内部パラメータの計算
 チェスボードの画像を20枚ほど撮影できたら、それらの画像を使って補正用のパラメータを計算していきます。
 ソースコードの中身はほとんど以下の参考ページ様からのコピペです。

・calcCamera.py

#
# カメラの歪みを戻すための値を計算する
#
import numpy as np
import cv2
import glob
from time import sleep
from datetime import datetime

TMP_FOLDER_PATH = "./tmp/"
MTX_PATH = TMP_FOLDER_PATH + "mtx.csv"
DIST_PATH = TMP_FOLDER_PATH + "dist.csv"

# メイン関数
def main():
    calcCamera() # カメラの歪みを計算

# カメラの歪みを計算する関数
def calcCamera():
    square_size = 20.0      # 正方形のサイズ(mm)
    pattern_size = (9, 6)  # 模様のサイズ
    pattern_points = np.zeros( (np.prod(pattern_size), 3), np.float32 ) #チェスボード(X,Y,Z)座標の指定 (Z=0)
    pattern_points[:,:2] = np.indices(pattern_size).T.reshape(-1, 2)
    pattern_points *= square_size
    obj_points = []
    img_points = []
 
    for fn in glob.glob("./img/*"):
        # 画像の取得
        im = cv2.imread(fn,0)
        print ("loading..." + fn)
        # チェスボードのコーナーを検出
        found, corner = cv2.findChessboardCorners(im, pattern_size)
        # コーナーがあれば
        if found:
            term = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_COUNT, 30, 0.1)
            corners2 = cv2.cornerSubPix(im, corner, (5,5), (-1,-1), term)
            # マークをつけて画像保存
            img = cv2.drawChessboardCorners(im, pattern_size, corners2, found)
            saveImgByTime(TMP_FOLDER_PATH, img)
            sleep(1)
        # コーナーがない場合のエラー処理
        if not found:
            print ('chessboard not found')
            continue
        img_points.append(corner.reshape(-1, 2))   #appendメソッド:リストの最後に因数のオブジェクトを追加
        obj_points.append(pattern_points)
 
    # 内部パラメータを計算
    rms, K, d, r, t = cv2.calibrateCamera(obj_points, img_points, (im.shape[1],im.shape[0]), None, None)

    # 計算結果を表示
    print ("RMS = ", rms)
    print ("K = \n", K)
    print ("d = ", d.ravel())

    # ファイル保存
    saveCalibrationFile(K, d, MTX_PATH, DIST_PATH)

# キャリブレーションCSVファイルを上書き保存する関数
def saveCalibrationFile(mtx, dist, mtx_path, dist_path):
    np.savetxt(mtx_path, mtx, delimiter =',',fmt="%0.14f")   #カメラ行列の保存
    np.savetxt(dist_path, dist, delimiter =',',fmt="%0.14f") #歪み係数の保存

# 画像を時刻で保存する関数
def saveImgByTime(dirPath, img):
    # 時刻を取得
    date = datetime.now().strftime("%Y%m%d_%H%M%S")
    path = dirPath + date + ".png"
    cv2.imwrite(path, img) # ファイル保存
    print("saved: ", path)

if __name__ == '__main__':
    main()

 calcCamera関数の「square_size = 20.0 # 正方形のサイズ(mm)」のところは1で使用したチェスボードのマス1辺の長さの値に書き換えてください。

 プログラムを少し説明すると、チェスボードの角を検出し、その角からカメラの内部パラメータ(レンズの歪みなど)を計算しています。

 使い方としては上記のプログラムを「calcCamera.py」として保存し、同じ階層に「img」フォルダと「tmp」フォルダを作成します。そしてimgフォルダ内に2で撮影した画像を全て入れ、calcCamera.pyを実行します。
 「tmp」フォルダに角を検出した結果の各白黒画像とカメラの内部パラメータを保存した「mtx.csv」と「dist.csv」が保存されます。


4:内部パラメータを使って画像を補正
 内部パラメータを保存した「mtx.csv」と「dist.csv」を使って画像を補正していきます。

・calibrate.py

#
# カメラの歪みを補正する
#
import numpy as np
import cv2
import glob
from time import sleep
from datetime import datetime

TMP_FOLDER_PATH = "./tmp/"
MTX_PATH = TMP_FOLDER_PATH + "mtx.csv"
DIST_PATH = TMP_FOLDER_PATH + "dist.csv"
SAVE_FOLDER_PATH = "./result/"

# メイン関数
def main():
    calibrateImage() # 画像の歪みを補正

# カメラの歪みをCSVファイルを元に補正する関数
def calibrateImage():
    mtx, dist = loadCalibrationFile(MTX_PATH, DIST_PATH)

    for fn in glob.glob("./img/*"):
        img = cv2.imread(fn)
        resultImg = cv2.undistort(img, mtx, dist, None) # 内部パラメータを元に画像補正
        saveImgByTime(SAVE_FOLDER_PATH, resultImg)
        sleep(1)

# キャリブレーションCSVファイルを読み込む関数
def loadCalibrationFile(mtx_path, dist_path):
    try:
        mtx = np.loadtxt(mtx_path, delimiter=',')
        dist = np.loadtxt(dist_path, delimiter=',')
    except Exception as e:
        raise e
    return mtx, dist

# 画像を時刻で保存する関数
def saveImgByTime(dirPath, img):
    # 時刻を取得
    date = datetime.now().strftime("%Y%m%d_%H%M%S")
    path = dirPath + date + ".png"
    cv2.imwrite(path, img) # ファイル保存
    print("saved: ", path)

if __name__ == '__main__':
    main()

 上記をコピペして「calibrate.py」という名前でcalcCamera.pyと同じ階層に保存します。また同じ階層に「result」フォルダも作成します。
 その状態で実行すると、tmpフォルダの中にあるmtx.csvとdist.csvを読み込み、その値を使ってimgフォルダの中にある画像を補正したものがresultフォルダの中に保存されます。

 ちなみに自分がやった感じだと以下のようになりました。

  • 元画像

f:id:rikoubou:20190326142524p:plain

  • 補正後

f:id:rikoubou:20190326142549p:plain


 以上がpythonOpenCVを使ってカメラの歪み補正を行う方法です。

 あくまでOpenCVがカメラの歪みを推定しているだけなので完璧な補正というわけにはいきませんが、ぱっと見で違和感ない程度には補正されているのがわかるかと思います。それと補正時に元画像の一部がカットされてしまうので注意が必要です。

 画像解析などをする際には歪みがあると何かと面倒だったりする場合もあるので、この方法を使うと何かといいかもしれません。


 またコピペしたりフォルダを作成したりするのが面倒な人もいるかと思うので、3と4のソースコードを1つにまとめた「calibrateCamera.py」やその他諸々をまとめたzipファイルを以下に公開しておきます。必要な方はご自由にどうぞ。


・参考資料

【MacOS】特定のファイルを含まずにzip圧縮する方法

 MacOSユーザーならわかるかとは思いますが、気づいたらディレクトリに「.DS_Store」というファイルが作成されています。これ自体はMac側が管理しやすくするための隠しファイルらしく、ウイルスなどではなく特にあっても問題はありません。

 ですが、Windows側とのファイルの受け渡しなどで「.DS_Store」というファイルまで入っているとなんだか気持ちが悪いです。

 なので今回は上記のようにzip圧縮する際に特定のファイルを含めないコマンドの紹介です。


・特定のファイルを含まずにzip圧縮するコマンド
 以下のコマンドでできます。

$ zip [保存したいzipファイル名].zip -r [圧縮したいディレクトリ名]/ -x "[含めたくないファイル名]"

 具体例として「hogeDirというディレクトリをhogeDir.zipに圧縮する際、.DS_Storeを除外する」という場合は以下のようなコマンドになります。

$ zip hogeDir.zip -r hogeDir/ -x "*.DS_Store"


 以上が特定のファイルを含まずにzip圧縮する方法です。参考資料にあるページ様に、まさに欲しい情報があったので助かりました。


・参考資料

【python/OpenCV/dlib】dlibとOpenCVを使って顔認識をする

rikoubou.hatenablog.com

 前回の記事でdlibをインストールしました。今回はそのdlibとOpenCVを使って顔認識をしていきます。

 では始めます。


1:学習済みデータのダウンロード
 顔の認識には学習済みのデータを使用します。

 上記のページを開き、一番下にある「shape_predictor_68_face_landmarks.dat.bz2」というファイルをダウンロードします。
f:id:rikoubou:20190314170724p:plain
 ファイルをダウンロードして解凍すると「shape_predictor_68_face_landmarks.dat」という学習済みデータであるdatファイルが作成されるので、これを利用していきます。(解凍すると100MBほどになるので注意してください)


2:顔認識のサンプルコード
 以下の内容をコピペして「dlibTest.py」というファイル名で保存します。

・dlibTest.py

#
# dlibとOpenCVを使った顔認識
#
import cv2
import dlib

def main():
	detector = dlib.get_frontal_face_detector()
	predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat") # 学習済みファイル読み込み

	cap = cv2.VideoCapture(0) # 任意のカメラ番号に変更する

	while True:
		ret, frame = cap.read()

		k = cv2.waitKey(1)&0xff # キー入力を待つ
		if k == ord('q'):
			# 「q」キーが押されたら終了する
			break
		
		# 画面サイズを1/2にする
		height = frame.shape[0]
		width = frame.shape[1]
		frame = cv2.resize(frame , (int(width/2), int(height/2)))

		img = frame * 0
		dets = detector(frame[:, :, ::-1])
		if len(dets) > 0:
			parts = predictor(frame, dets[0]).parts() # 顔の点を取得

			# 確認
			for i in parts:
				# cv2.circle(frame, (i.x, i.y), 1, (255, 0, 0), -1)
				cv2.circle(img, (i.x, i.y), 1, (255, 0, 0), -1) # 点をプロット

		# cv2.imshow("camera", frame) # 画像を表示
		cv2.imshow("camera", img) # 画像を表示

	# キャプチャをリリースして、ウィンドウをすべて閉じる
	cap.release()
	cv2.destroyAllWindows()

if __name__ == '__main__':
	main()

 保存したらdlibTest.pyと同じ階層に1で準備した「shape_predictor_68_face_landmarks.dat」ファイルを配置します。
f:id:rikoubou:20190314171029p:plain

 Webカメラを繋げた状態でdlibTest.pyを実行すると以下のように顔の特徴点をとらえた画像が表示されます。
f:id:rikoubou:20190314171343p:plain


 以上がdlibとOpenCVを使って顔認識をする方法です。

 OpenCVだけでも顔認識などはできましたが、dlibを使った方がより精度が高く表情などが取れると思います。
 

・参考資料

【python】MacOSにdlibをインストールする

 OpenCVでも顔の検知はできますが、より精度の高い顔の検知をするためのライブラリとして「dlib」というのがあるのを知りました。

 今回はそのdlibをインストールする方法です。

 基本的にはpipが入っていればコマンド一つでインストールできるのですが、自分の場合は色々とエラーが起きたりしたのでその対処法も含めて紹介します。

 では始めます。


1:前提条件
 前提条件として以下のものがインストールされていることが必要です。

 インストールできてない場合は、自分の環境構築をした時の記事があるので参考にしてください。


2:dlibのインストール方法
 基本的には以下のコマンドでインストールできます。

$ pip install dlib

 上記のコマンドを実行して以下のようなエラーが出る場合があります。
f:id:rikoubou:20190313152251p:plain

 エラーにある通りに以下のコマンドを実行してpipをアップグレードします。

$ pip install --upgrade pip

 pipのアップグレードが完了したら「pip install dlib」コマンドをもう一度実行します。

 それでも以下のようなエラーが発生する場合があります。

    RuntimeError:
    *******************************************************************
     CMake must be installed to build the following extensions: dlib
    *******************************************************************

 このエラーが発生した場合はCMakeのインストールが必要なので以下のコマンドでCMakeをインストールします。

$ brew install cmake

 Cmakeのインストールには割と時間がかかります。

 ここまでできたらもう一度「pip install dlib」コマンドを実行すればインストールできるはずです。

 dlibがインストールできたかはimportしてエラーが出ないことで確認できます。
f:id:rikoubou:20190313152904p:plain


 以上がdlibのインストール方法です。

 コマンド一つでなかなか通らないこともありちょっと時間がかかったので、参考になれば幸いです。


・参考資料

【python/OpenCV】カメラ映像をキャプチャするプログラム

 pythonOpenCVを使って色々やってきた中で今更な感じですが、今回はカメラ画像を任意のタイミングで気軽に画像として保存できるようにするプログラムです。
 画像認識などを行う場合にはサンプルとして様々な画像を取得する必要があったりします。「楽してカメラのキャプチャを取れるようにしたい」という思いから自分が作ってみたので、その紹介です。


・カメラのキャプチャ画像を取得するプログラム
・saveCameraImg.py

#
# カメラ画像をキャプチャする
#
import cv2
from datetime import datetime

cap = cv2.VideoCapture(0) # 任意のカメラ番号に変更する

while True:
    ret, frame = cap.read()
    cv2.imshow("camera", frame)

    k = cv2.waitKey(1)&0xff # キー入力を待つ
    if k == ord('p'):
        # 「p」キーで画像を保存
        date = datetime.now().strftime("%Y%m%d_%H%M%S")
        path = "./img/" + date + ".png"
        cv2.imwrite(path, frame) # ファイル保存

        cv2.imshow(path, frame) # キャプチャした画像を表示
    elif k == ord('q'):
        # 「q」キーが押されたら終了する
        break

# キャプチャをリリースして、ウィンドウをすべて閉じる
cap.release()
cv2.destroyAllWindows()

 使い方としては、上記のプログラムをコピペして「saveCameraImg.py」というファイル名で保存して同じ階層に「imgフォルダ」を作成します。
f:id:rikoubou:20190307151838p:plain

 saveCameraImg.pyを実行するとカメラの映像が表示されるので「p」キーを押してキャプチャ、「q」キーを押して終了します。
 画像は秒単位の現在時刻でimgフォルダ内に保存されます。


 以上がカメラ画像をキャプチャするプログラムです。地味ですがこういうちょっとしたツールのようなものを作っておくと作業が楽になったりするので自由に使ってください。
 またコピペしたりフォルダ作るのが面倒という人もいるかもしれないので、以下のリンクに解凍するだけで使えるzipファイルを公開しておきます。

【python】pythonを使った最小二乗法でデータから数式を推定する方法

 今回はタイトルにある通り、pythonを使ってデータから数式を推定する方法の備忘録です。

 最小二乗法とか難しい言葉を使ってはいますが、要は「データをプロットすると一定の法則性があって数式化できそう」という場合に用いる方法になります。

 詳しい理論などは置いておいて、とりあえずデータから数式を推定するという部分のみの解説になるので注意してください。

 では始めます。


0:matplotlibを使えるようにする
 今回はmatplotlibというライブラリを使います。importしようとしてもエラーが発生する場合は以下の参考にさせていただいたページ様のやり方で解決できます。

 要は以下のコマンドを実行して、そのファイルの中身を開いて「backend : macosx」となっているところを「backend : Tkagg」に書き換えるというだけです。

$ python -c "import matplotlib;print(matplotlib.matplotlib_fname())"

 この方法はMacOSのみの場合なので、Windowsでエラーが出て使えない場合は各自で調べるようお願いします。


1:データの準備
 それでは本筋に入っていきますが、事前準備としてデータを準備します。今回は以下の適当なデータを使うことにします。

・x.csv

180,211,224,235,247,256,265,271,275,279,284,287,289,292,295,296,298,300,301,302,304,302,306,306,308,309,309

・y.csv

357,337,329,322,315,311,305,301,298,295,293,293,290,288,286,287,285,284,282,282,282,281,281,279,279,278,279

 上記の2つのデータをそれぞれ「x.csv」、「y.csv」として保存したファイルを使って以降の話を進めていきます。


2:データのプロット
 まずは上記のデータをプロットしたグラフを作成して傾向を見てみます。

 以下のプログラムをコピペして「dataPlot.py」という名前で保存します。

・dataPlot.py

#
# データプロット
#
import numpy as np
from matplotlib import pyplot as plt

def main():
    X_CSV_PATH = "x.csv"
    Y_CSV_PATH = "y.csv"
    SAVE_NAME = "result.png"

    x, y = loadCSVFile(X_CSV_PATH, Y_CSV_PATH) # CSVファイルを読み込み
    plt.scatter(x , y)     # データプロット
    plt.savefig(SAVE_NAME) # グラフを画像として保存

# CSVファイルを読み込む関数
def loadCSVFile(x_path, y_path):
    try:
        x_csv = np.loadtxt(x_path, delimiter=',')
        y_csv = np.loadtxt(y_path, delimiter=',')
    except Exception as e:
        raise e
    return x_csv, y_csv

if __name__ == '__main__':
    main()

 少し解説すると、「x_csv = np.loadtxt(x_path, delimiter=',')」、「y_csv = np.loadtxt(y_path, delimiter=',')」のところで第一引数のファイルパスをCSVとして読み込んでnumpyの配列として取得しています。この取得したデータを「plt.scatter(x , y)」に入れてグラフにプロットし、「plt.savefig(SAVE_NAME)」で画像として保存しています。

 pythonのファイルを作成したら、次は以下のように同じ階層にx.csvとy.csvを配置します。
f:id:rikoubou:20190228172205p:plain

 その状態でdataPlot.pyを実行すると「result.png」という名前でグラフの画像ファイルが作成されます。
f:id:rikoubou:20190228172301p:plain

 このグラフの傾向を見ると、直線の一次関数(y = ax + b)に近い形でデータがプロットされていることがわかります。


3:数式の推定
 2でデータをプロットしたことにより、なんとなく一次関数っぽくなっていることがわかりました。
 ここからは実際に数式を推定していきます。

 数式の推定にはpythonのライブラリであるnumpyの「polyfit関数」を使えば計算できます。

coefficient = np.polyfit([Xデータ], [Yデータ], [次元数])

 第一引数にXのデータ、第二引数にYのデータ、第三引数に次元数(整数)を入力すれば係数を計算してくれます。例えば次元数を3にすると「y = ax^3 + bx^2 + cx + d」の数式の各係数a,b,c,dの4つを得ることができます。
 またこれらの係数を使った数式のグラフは以下の記述で作成できます。

plt.plot(x, np.poly1d(coefficient)(x)) # グラフを記述

 係数の計算方法とグラフの記述方法がわかったので、2のプログラムにこの係数を推定する記述を追加して計算してみます。

・dataPlot2.py

#
# データプロットと次元の計算
#
import numpy as np
from matplotlib import pyplot as plt

def main():
    DIMENSION = 1 # 次元数

    X_CSV_PATH = "x.csv"
    Y_CSV_PATH = "y.csv"
    SAVE_NAME = "result.png"

    x, y = loadCSVFile(X_CSV_PATH, Y_CSV_PATH) # CSVファイルを読み込み
    plt.scatter(x , y)     # データプロット

    coefficient = np.polyfit(x, y, DIMENSION) # 係数を計算
    print(coefficient) # 係数を確認

    plt.plot(x, np.poly1d(coefficient)(x)) # グラフを記述

    plt.savefig(SAVE_NAME) # グラフを画像として保存

# CSVファイルを読み込む関数
def loadCSVFile(x_path, y_path):
    try:
        x_csv = np.loadtxt(x_path, delimiter=',')
        y_csv = np.loadtxt(y_path, delimiter=',')
    except Exception as e:
        raise e
    return x_csv, y_csv

if __name__ == '__main__':
    main()

 実行すると以下のように係数とグラフが得られます。

・係数

[ -0.60376793 464.66578936]

・グラフ
f:id:rikoubou:20190228174553p:plain

 グラフを見る限り、割と合っていそうな感じがします。


 以上がpythonを使ってデータから数式を推定する方法です。

 あらかじめ係数を計算しておきcoefficientを定数として持っておけば、他のxのデータが入ってきても推定した数式からおおよそのyの値を得ることができます。ちょっとした傾向などから値を推測する程度であればこのやり方で十分かと思います。
 ライブラリを使って楽に数式を作れるのはありがたいですね(正直原理はちゃんと理解していないです…)。

 また参考資料で紹介しているサイト様で他の関数を使った数式の推定も行なっているので、気になる方はそちらも参照してください。

 最近はビッグデータだなんだと言われる時代でもあるので、ちょっとだけでもデータを使って色々できるようになりたいです。

 今回作成したプログラムと使用したCSVを公開しておきます。


・参考資料

【python/OpenCV】画像の特定の色を抽出する方法

 今回はpythonOpenCVを使って画像の特定の色を抽出する方法の備忘録です。
 OpenCVでは2つの方法で特定の色を抽出できるので、その2つの方法を説明していきます。

 では始めます。


1:RGBでの色抽出方法
 まず一つ目の方法としてRGBでの色の抽出方法があります。その方法は以下の記述でできます。

import cv2
import numpy as np

image = cv2.imread('./test1.png') # ファイル読み込み

# BGRでの色抽出
bgrLower = np.array([102, 255, 255])    # 抽出する色の下限(BGR)
bgrUpper = np.array([102, 255, 255])    # 抽出する色の上限(BGR)
img_mask = cv2.inRange(image, bgrLower, bgrUpper) # BGRからマスクを作成
result = cv2.bitwise_and(image, image, mask=img_mask) # 元画像とマスクを合成

 ※OpenCVでは「RGBではなくBGRになっている」ので色の順番には注意してください。

 抽出する色の上限下限を作成してinRange関数でマスクを取得します。そのマスクを元画像に適応するとこで、範囲内の色以外を黒くするという方法になっています。


2:HSVでの色抽出方法
 もう一つの方法としてHSVでの色の抽出方法があります。

 HSVとは「色相(Hue)・彩度(Saturation)・明度(Value)」で色を表したもので、以下のリンクからRGB・HSVの変換ができます。

 ちなみにOpenCVでのそれぞれの範囲は以下の通りとなっています。

名称 値の範囲 備考
色相(H) 0〜180 本来は0〜360だがOpenCVでは1/2の範囲になる
彩度(S) 0〜255 値が0に近づくほど白く、255に近づくほどHの色になる
明度(V) 0〜255 値が0に近づくほど黒く、255に近づくほどHの色になる

 そのHSVを使った色の抽出方法は以下の記述でできます。

import cv2
import numpy as np

image = cv2.imread('./test1.png') # ファイル読み込み

# HSVでの色抽出
hsvLower = np.array([30, 153, 255])    # 抽出する色の下限(HSV)
hsvUpper = np.array([30, 153, 255])    # 抽出する色の上限(HSV)
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 画像をHSVに変換
hsv_mask = cv2.inRange(hsv, hsvLower, hsvUpper)    # HSVからマスクを作成
result = cv2.bitwise_and(image, image, mask=hsv_mask) # 元画像とマスクを合成

 1の手法と似ていますが、上限下限がHSVになっているのと一度画像をHSV形式に変換しているところが違っています。


3:実装例
 色抽出の方法がわかったので実際に以下の画像から背景色を抽出してみたいと思います。
f:id:rikoubou:20190221185338p:plain

 上記の画像を「test1.png」として保存し、同じ階層に以下のファイルを作成して実行します。

・colorExtraction.py

#
# 色抽出のサンプルコード
#
import numpy as np
import cv2
from time import sleep

# メイン関数
def main():
    image = cv2.imread('./test1.png') # ファイル読み込み

    # BGRでの色抽出
    bgrLower = np.array([102, 255, 255])    # 抽出する色の下限
    bgrUpper = np.array([102, 255, 255])    # 抽出する色の上限
    bgrResult = bgrExtraction(image, bgrLower, bgrUpper)
    cv2.imshow('BGR_test1', bgrResult)
    sleep(1)

    # HSVでの色抽出
    hsvLower = np.array([30, 153, 255])    # 抽出する色の下限
    hsvUpper = np.array([30, 153, 255])    # 抽出する色の上限
    hsvResult = hsvExtraction(image, hsvLower, hsvUpper)
    cv2.imshow('HSV_test1', hsvResult)
    sleep(1)

    while True:
        # キー入力を1ms待って、keyが「q」だったらbreak
        key = cv2.waitKey(1)&0xff
        if key == ord('q'):
            break

    cv2.destroyAllWindows()


# BGRで特定の色を抽出する関数
def bgrExtraction(image, bgrLower, bgrUpper):
    img_mask = cv2.inRange(image, bgrLower, bgrUpper) # BGRからマスクを作成
    result = cv2.bitwise_and(image, image, mask=img_mask) # 元画像とマスクを合成
    return result

# HSVで特定の色を抽出する関数
def hsvExtraction(image, hsvLower, hsvUpper):
    hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 画像をHSVに変換
    hsv_mask = cv2.inRange(hsv, hsvLower, hsvUpper)    # HSVからマスクを作成
    result = cv2.bitwise_and(image, image, mask=hsv_mask) # 元画像とマスクを合成
    return result


if __name__ == '__main__':
    main()

 すると以下のようにどちらの方法でも背景色のみが抽出できます。
f:id:rikoubou:20190221185739p:plain


 以上がpythonOpenCVで特定の色を抽出する方法です。

 基本的に画像から色を抽出する時ははっきりとした色ではなくグラデーションがある場合が多いです。
 どちらか一方だけではなく、画像の内容や目的によってBGRの方法とHSVの方法を使い分ける必要が出てくるかと思います。


・参考資料