とある科学の備忘録

とある科学の備忘録

CやPythonのプログラミング、Arduino等を使った電子工作をメインに書いています。また、木製CNCやドローンの自作製作記も更新中です。たまに機械学習とかもやってます。

Python+OpenCVで画像処理 勉強会第一回(物体認識、背景削除)

にゃんぱすー!
大学の某サークルの画像処理関連の勉強会の内容です。


この記事では、以下の内容について語っていきます

  • Python + OpenCVの環境構築
  • OpenCVの基本的な使い方
    • 画像の読み込み・表示
    • カメラ画像の読み込み・表示
    • 各種エフェクト
      • 二値化
      • グレースケール変換
      • エッジ抽出
      • ブラー(ぼかし)
      • 色空間変換(RGB↔HSV等)
  • カメラの背景画像を削除する
  • 物体検知(機械学習を使わずに)

プログラム全体はGitHubの↓レポジトリに上がっているよ
github.com
  

ではいこう!



環境構築

基本的にWindowsの前提で話します。Macの人は頑張って下さい(ネット上に記事が大量にあるはず)

Pythonのインストール

自分のPCでPythonプログラムが実行できるような環境を整えます

www.python.org

上記リンクから、最新のPythonをダウンロードします。2021/6/5時点では、Python3.9.5が最新なので、それをクリックします。
そして、Files節の自分のOSに合ったインストーラーをダウンロードします。

かなぁ。(間違ってたらごめんなさい)

インストール中に、「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です

ちなみに、pipPythonの標準パッケージインストーラーです。

pipで必要モジュールのインストール

では、そのpipを使って画像処理用ライブラリ「OpenCV」と行列計算ライブラリ「numpy」をインストールします。

$ pip install numpy
$ pip install opencv-python
$ pip install opencv-contrib-python

 

VSCodeの設定

Python拡張機能を入れておくと便利です。補完機能や、デバッグの効率化、インデント色付け、ボタン一つでPythonプログラムを実行など色々あります。
VSCodeの左枠の拡張機能アイコン(f:id:pythonjacascript:20210605071017p:plain)をクリックすると拡張機能一覧が表示されるので、「Python」とかで検索していい感じのものを入れましょう



ここからが本題です。プログラミングを始めます。この記事の通りにプログラムを書いて実行していっても良いですが、このレポジトリをzipダウンロード→解凍して使ったほうが楽かも。

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

プログラムの実行の仕方は、

  1. 「hogehoge.py」みたいに「.py」拡張子で名前を付けて保存して下さい。
  2. pyファイルと同じ位置にcat.jpgという名前で適当な画像をおいて下さい。(この記事ではこれを使います)
  3. コマンドプロンプトで「python hogehoge.py」のように「python [スクリプトファイル名]」と打って、プログラムを実行


以下のように「test」Windowに猫の画像が表示されたでしょうか?

f:id:pythonjacascript:20210605083336j:plain

説明はスクリプトに書いてあるので読んでね。それでもわからない部分はググってね

2. 各種エフェクト

imread関数で読み込んだ画像オブジェクトに、ぼかしエフェクトを加えてみます。
以下の一文をimread関数とimshow関数の間に追加して下さい。

img = cv2.blur(img,(51,51))

「(51, 51)のサイズでimgにブラー(ぼかし)を加えて、結果をimgに代入する」、という動作

以下の画像のようになったでしょうか?
f:id:pythonjacascript:20210605090544p:plain

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 ブラー(平滑化) f:id:pythonjacascript:20210605084216j:plain
G グレースケール(白黒化) f:id:pythonjacascript:20210605084750j:plain
E エッジ抽出 f:id:pythonjacascript:20210605084707j:plain
X 油絵エフェクト(こんなのもある。面白いなぁ) f:id:pythonjacascript:20210605084240j:plain
H 色空間をRGBからHSVにする f:id:pythonjacascript:20210605084619j:plain
B 大津の二値化(白黒二色にする) f:id:pythonjacascript:20210605084229j:plain
W 緑っぽい部分を青色(RGB(0, 0, 255)) にする f:id:pythonjacascript:20210605084508j:plain
V 輪郭を描画(自作スクリプト) f:id:pythonjacascript:20210605084408j:plain

という処理を実行します。


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

 


4. 背景削除

ここからは問題形式。

f:id:pythonjacascript:20210605090013j:plain

  • カメラ画像から背景を削除する
  • Zoomのバーチャル背景みたいな機能を実装する
  • 人がいないときのカメラ映像は持っているものとする

  

  


5. 物体認識(画像編)

問題設定

flower.jpgがある
ここから赤のチューリップを認識して四角の枠で囲もう

例:
f:id:pythonjacascript:20210605085053j:plain
 
  

6. 物体認識(カメラ編)

4.と5.を組み合わせて、以下のようなものを作る

カメラ画像を取得して、その中にある物体を検出して四角で囲む

例:
f:id:pythonjacascript:20210605091942g:plain