Python+OpenCVで画像処理 勉強会第一回(物体認識、背景削除)
にゃんぱすー!
大学の某サークルの画像処理関連の勉強会の内容です。
この記事では、以下の内容について語っていきます
- Python + OpenCVの環境構築
- OpenCVの基本的な使い方
- 画像の読み込み・表示
- カメラ画像の読み込み・表示
- 各種エフェクト
- 二値化
- グレースケール変換
- エッジ抽出
- ブラー(ぼかし)
- 色空間変換(RGB↔HSV等)
- カメラの背景画像を削除する
- 物体検知(機械学習を使わずに)
プログラム全体はGitHubの↓レポジトリに上がっているよ
github.com
ではいこう!
環境構築
基本的にWindowsの前提で話します。Macの人は頑張って下さい(ネット上に記事が大量にあるはず)
Pythonのインストール
自分のPCでPythonプログラムが実行できるような環境を整えます
上記リンクから、最新のPythonをダウンロードします。2021/6/5時点では、Python3.9.5が最新なので、それをクリックします。
そして、Files節の自分のOSに合ったインストーラーをダウンロードします。
- Windows→「Windows installer (64-bit)」
- intel製Mac→「macOS 64-bit Intel installer」
- M1 Mac→「macOS 64-bit universal2 installer」
かなぁ。(間違ってたらごめんなさい)
インストール中に、「Add Python 3.x to PATH(Pythonを環境変数に追加する)」のような表示が出たらチェックすることを忘れずに!!
インストールが正常に終わっていると、ターミナル(Windowsの人はデフォルトではコマンドプロンプト。でもWindows Terminalを入れておくことをおすすめします)で以下のコマンドを実行してみて下さい。
$ python --version Python 3.8.5 $ pip --version pip 20.0.2 from /usr/lib/python3/dist-packages/pip (python 3.8)
※「$」マークは「これはコマンドだよ」というのを表す記号なので、入力しないで下さい。
※上のようにしてエラーが出る場合はpython→python3, pip→pip3に置き換えて見て下さい
上のように、バージョンが表示されればOKです
pipで必要モジュールのインストール
では、そのpipを使って画像処理用ライブラリ「OpenCV」と行列計算ライブラリ「numpy」をインストールします。
$ pip install numpy $ pip install opencv-python $ pip install opencv-contrib-python
1. 画像を表示してみる
以下のプログラムを実行して下さい。
# https://github.com/20niship/python_opencv_lecture/blob/master/1_1_show_img%20copy.py # OpenCVライブラリを読み込む import cv2 # 画像を読み込んでimg変数に格納 # print(img)をするとわかるが、imgはw * h * 3の大きさのnumpy行列 img = cv2.imread("cat.jpg") while True: # testウィンドウにimgを表示 cv2.imshow("test", img) # 10ms待つ。その間になにかキーボードが押されたらその数値を返してkeyに代入 key = cv2.waitKey(10) # print(key) # ESCキーやQキーが押された場合は終了する if key == 27 or key == 113: break
プログラムの実行の仕方は、
- 「hogehoge.py」みたいに「.py」拡張子で名前を付けて保存して下さい。
- pyファイルと同じ位置にcat.jpgという名前で適当な画像をおいて下さい。(この記事ではこれを使います)
- コマンドプロンプトで「python hogehoge.py」のように「python [スクリプトファイル名]」と打って、プログラムを実行
以下のように「test」Windowに猫の画像が表示されたでしょうか?
説明はスクリプトに書いてあるので読んでね。それでもわからない部分はググってね
2. 各種エフェクト
imread関数で読み込んだ画像オブジェクトに、ぼかしエフェクトを加えてみます。
以下の一文をimread関数とimshow関数の間に追加して下さい。
img = cv2.blur(img,(51,51))
「(51, 51)のサイズでimgにブラー(ぼかし)を加えて、結果をimgに代入する」、という動作
以下の画像のようになったでしょうか?
blur関数の第二引数を色々変えてみると、ブラーの強さが変化します
blur関数が何をやっているのかは公式ドキュメントを見てね(行列をかけてる)
今度は、キーボードの入力で適応されるエフェクトが変化するスクリプトを作ってみます。
こーんな感じ。
python_opencv_lecture/1_2_effects.py at master · 20niship/python_opencv_lecture · GitHub
import cv2 import numpy as np # 行列計算ライブラリ、Numpyをインポート key = 0 while True: img = cv2.imread("cat.jpg") # image read # 画像にエフェクトをかけていく if key is ord('a'): # Aが押された時 img = cv2.blur(img,(15,31)) # 画像をぼかす(15, 35)はX,Y方向のぼかす大きさ elif key is ord('g'): img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # グレースケールにする elif key is ord('e'): img = cv2.Canny(img,60,200) # 輪郭抽出 elif key is ord('x'): # 油絵エフェクト # 第二引数はsize, 第三引数はdynRatio img = cv2.xphoto.oilPainting(img, 7, 2, cv2.COLOR_BGR2Lab) elif key is ord('h'): # 色空間の変換(RGB -> HSV) img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) elif key is ord('b'): gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # グレースケールにする ret3,img = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU) # 大津の二値化 # 上のようなエフェクト組み合わせて色々作っていくよ # 例1:グリーンバック elif key is ord('w'): hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 色空間の変換(RGB -> HSV) height, width, channel = img.shape print(hsv[10, 10]) for x in range(width): for y in range(height): h, s, v= img[y, x] if 30 < h < 70 and s > 50: # 緑色の部分は img[y, x]=[255, 0, 0] # 赤色にする # 例2:自力で輪郭抽出 elif key is ord('v'): gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # グレースケール化 ret3,img_binary = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU) # 二値化 img_binary = cv2.bitwise_not(img_binary) # ネガポジ反転(findContours関数は白い部分を検出するため) contours, hierarchy = cv2.findContours(img_binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # 輪郭検出 img = cv2.drawContours(img, contours, -1, (0, 255, 0), 5) # 輪郭描画 cv2.imshow("test", img) key_tmp = cv2.waitKey(10) if key_tmp > 0: key = key_tmp if key == 27 or key == 113: break
プログラムを実行して、
押したキー | 内容 | 出力画像 |
---|---|---|
A | ブラー(平滑化) | |
G | グレースケール(白黒化) | |
E | エッジ抽出 | |
X | 油絵エフェクト(こんなのもある。面白いなぁ) | |
H | 色空間をRGBからHSVにする | |
B | 大津の二値化(白黒二色にする) | |
W | 緑っぽい部分を青色(RGB(0, 0, 255)) にする | |
V | 輪郭を描画(自作スクリプト) |
という処理を実行します。
3. カメラ画像を取得
PCにカメラがあれば(もしくはUSBカメラ等が繋がっていれば)、そのカメラ映像を表示することもできます。
import cv2 import numpy as np # 行列計算ライブラリ、Numpyをインポート # VideoCapture オブジェクトを取得 cap = cv2.VideoCapture(0) if cap.isOpened(): # get vcap property width = cap.get(cv2.CAP_PROP_FRAME_WIDTH) # float `width` height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) # float `height` # 以下の方法でも可 # width = cap.get(3) # float `width` # height = cap.get(4) # float `height` fps = cap.get(cv2.CAP_PROP_FPS) print("camera found!") print(f"width={width}, height={height}, fps={fps}") else: print("カメラが取得できない!") while(True): ret, img = cap.read() # 現在のカメラ画像を取得 # ここにエフェクトを追加していく cv2.imshow('camera',img) key = cv2.waitKey(10) if key == 27 or key == 113: break