OpenCV

Python で画像とキーボード入力

画像を用意

顔を描きましょう

  • PowerPoint あるいは Keynote で顔の絵(高さ400,幅400 程度)を描き,スクリーンショット( コマンドキー+Shift+4 ) でその画像を保存してください.

python で画像を表示

準備

画像の表示には OpenCV というライブラリを使います.これを使うためにopencv のライブラリをインストールします.

まずは

source ~/roboenv/bin/activate

で仮想環境を有効にしてください.

その後,以下のコマンドをターミナルで打ち込んでください.

pip install opencv-python

うまくインストールできているかは,python のインタラクティブモードで確かめることができます.

>>> import cv2
>>> 

のように import cv2 でエラーが出なければ,実行できているということになります.

プログラム

robot1.py に以下のように記述


import cv2

img = cv2.imread("face.png",0)

while 1:
    cv2.imshow('image',img)

    key = cv2.waitKey(10)
    if key == 27:  # ESC キーが入力されたら
        break

cv2.destroyAllWindows()

画像ファイル "face.png" が実行するプログラムと同じところにあるようにしてください.

授業では OpenCV という画像処理ライブラリを使います.ライブラリを使うには import ライブラリ名 のようにファイルの最初に宣言します.宣言した後は cv2.関数名 のようにライブラリの関数を使うことができます.

関数の説明

  • imread(ファイル名) :画像ファイルを読み込み,画像情報の変数を返します.
  • imshow(ウィンドウの名前, 画像データ):画像をウィンドウに表示
  • waitKey(待ち時間) :ユーザーのキー入力を受け付け,入力されたキーの情報を返します.
  • destroyAllWindows(): 開かれているすべてのウィンドウを閉じます.

python でキーボード

上のプログラムで if key==27 の部分で,押されたキーボードの判定をしていますが,この 27 は ESC キーの ASCII 文字コードです.文字コードを確かめたいときには,

>>> ord("a")
>>> 97

のように ord 関数をつかえばよいです.上のプログラムに

if key==ord("a"):
    print("aが押された!")

と書きたして,"a" が押されたときに「aが押された!」と出力されるか確かめてください.

画面に文字を出力する

以下はOpenCV を使って画面に文字を出力するプログラムです. 場所,色,フォントの種類,大きさなどを指定して,画像に書き込んで出力します.

"test_text.py"

# -*- coding: utf-8 -*-

import cv2

img = cv2.imread("face.png",1) 
            #1(カラーで読み込み)にする!

msg="Hello Python"

while 1:
    ########################
    #### キーボードの入力 ####
    ########################
    key = cv2.waitKey(10)
    if key == 27:  # ESC キー: 終了
        break
    if key == ord("a"):
        msg = "Hello Roomba"
        print("こんにちは")
    if key == ord("b"):
        msg = "Angry!"
        print("怒ったぞ!")

    #################################
    #### テキストを画像に書き込み ####
    #################################

    img2 = img.copy()  #書き込み用に画像をコピー

    # テキストの設定
    location=(0,30)   # テキストを出力する位置
    color=(255,0,0)   # テキストの色 rgb の 0~255
    fontface=cv2.FONT_HERSHEY_PLAIN  #フォント
    fontscale=2     #フォントの大きさ
    thickness=2     #フォントの太さ

    # 画像に書き込み
    cv2.putText(img2, msg, location, fontface, fontscale, color) 

    ###################
    #### 画像の表示 ####
    ##################

    cv2.imshow('image',img2)

# 終了時の処理
cv2.destroyAllWindows()

怒った(困った?)顔

前回は一つの顔だけでしたが,今回はそれを入れ替えることをやってみましょう.

まずはお絵描きソフト(Seashore.app)で怒った(あるいは困った)顔の画像を作成し,それを "okotta.png" で保存してください。

そして以下のプログラムを "test_face.py" として保存し実行してください.

# -*- coding: utf-8 -*-

import cv2

img = cv2.imread("face.png",1) 
img2 = cv2.imread("okotta.png",1)

mode=1

while 1:

    ########################
    #### キーボードの入力 ####
    ########################

    key = cv2.waitKey(30)
    if key == 27:  # ESC キーが入力されたら
        break
    if key == ord("a"):
        mode=1
        print ("こんにちは")
    if key == ord("b"):
        mode=2
        print ("怒ったぞ")

    ####################
    #### 画像の表示 ####
    ####################

    if mode==1:
        img3 = img.copy()
    if mode==2:
        img3 = img2.copy()

    cv2.imshow('image',img3)

# 終了時の処理
cv2.destroyAllWindows()

色を認識する

準備

以下のプログラムをダウンロードして同じディレクトリに置いてください.

$ python color_detect.py

としてプログラムを動かしてください.認識したい色の部分をカメラ画像のウィンドウでマウスで四角く囲みます(クリックだけではダメです).すると,黒い画面の方に認識された色が現れます. 処理としては,

  • 囲まれた領域でHSVの最小値と最大値を見つけ探索する色とする
  • カメラ画像の中からその範囲にある色のピクセルを検出
  • 検出された領域の中で__最大領域__を探す

として,その領域の中心の座標 (x,y) と領域の幅と高さ (w,h) を返します.色が認識されなかった場合,x, y には -1 が入っていますので,これで色が認識されたかどうかを識別することができます.

色は2色認識することができ,「0」キーを押すと0に相当する色を,「1」キーを押すと1に相当する色を登録することができます. また,登録した色は 「s」キーを押すとファイルに保存することができ,「l」キーを押すとファイルから現在のモード(0か1)の色として読み込むことができます.

# -*- coding: utf-8 -*-
import cv2
import coldet as col
#import coldet

#################################
# 初期設定
#################################

cap = cv2.VideoCapture(0)
cap.set(3,640)  # カメラの横のサイズ
cap.set(4,480)  # カメラの縦のサイズ

cv2.namedWindow('image')
cv2.setMouseCallback('image', col.pick_color)

 #################################
 # while ループ
 #################################
while True:
    ret, im = cap.read()
    if ret==True:
        imc = im.copy()

        col.im_hsv = cv2.cvtColor(imc, cv2.COLOR_BGR2HSV)

        im_green0, pos_x0, pos_y0, w0, h0 = col.detect_color(imc, 0)
        im_green1, pos_x1, pos_y1, w1, h1 = col.detect_color(imc, 1)
        #print( "(x,y)=", pos_x, ",", pos_y)
        cv2.imshow("green0",im_green0)
        cv2.imshow("green1",im_green1)
        cv2.imshow("image", imc)

    # キーが押されたらループから抜ける
    key = cv2.waitKey(10)
    if key==ord('q'):
          break
    elif key==ord('0'):
        print("color number=0")
        col.cn = 0
    elif key==ord('1'):
        print("color number=1")
        col.cn = 1
    elif key==ord('r'):
        col.reset_color()
    elif key==ord('s'):
        print("color saved")
        col.save_color("./color.csv")
    elif key==ord('l'):
        print("color load")
        col.load_color("./color.csv") 
 #################################
 # 終了処理
 #################################

# キャプチャー解放
cap.release()
# ウィンドウ破棄
cv2.destroyAllWindows()

データのセーブとロード

numpy にはデータを csv ファイルで保存する命令として,np.savetxt, np.loadtxt があります.これを使うと,毎回プログラムを起動するたびに色を登録する必要がなくなります.このために "coldet.py" に以下を追加してください.

def save_color(file_name):
    global cn
    global h_min, s_min, v_min
    global h_max, s_max, v_max

    col_data = np.array([h_min[cn], s_min[cn], v_min[cn], h_max[cn], s_max[cn], v_max[cn]])
    np.savetxt(file_name, col_data, delimiter=',',fmt="%d")

def load_color(file_name):
    global cn
    global h_min, s_min, v_min
    global h_max, s_max, v_max    


    if os.path.exists(file_name)==True:
        data = np.loadtxt(file_name, delimiter=',')
        col_data = np.array(data, dtype='int')
        h_min[cn], s_min[cn], v_min[cn] = col_data[0], col_data[1], col_data[2]
        h_max[cn], s_max[cn], v_max[cn] = col_data[3], col_data[4], col_data[5]

課題

  1. 普通の顔から,登録した1色目が見えたら怒るように,2色目が見えたら笑うようにプログラムを改変してください.

  2. 登録した色が遠いところに見えていたら怒る.近くに見えたら泣くようにプログラムを改変してください.

  3. 前回のプログラムを改変し、キーボードで a を押したら前に進む、 b を押したら後ろに進む、 c を押したら止まるようにしてください.

  4. 見える色によって振る舞いが変わるような(例えば、青が見えたら前進、赤が見えたら後退するような)プログラムを作ってみてください.