Welcome to Mashykom WebSite


OpenCV 入門

 画像処理のOSSとして最もシンプルな構造を持つソフトはOpenCV(Open Source Computer Vision)だと思われます。 1999年、Intelの Gary Bradskyによって開発され、 2000年に発表された。その後、Vadim Pisarevskyたちが加わり、2008年以降、Willow Garageの支援を得て、Open Sourceとして開発が活発に行われてきました。現在、OpenCVのバージョンは3.xです。Windows, Linux, OS Xなどのクロス・プラットホームで作動します。利用できる言語はPython, C++, Javaなどです。

 このページでは、OpenCV-Python、つまり、the Python API of OpenCVを用います。個人的理由からMacOS上で使用しますが、WindowsやLinuxなどと異なるのはインストールの仕方だけです。OpenCV 4.xバージョンを使用します。言語環境としては基本的にはPythonとそのモジュールNumpyとMatplotlibが必須です。ここでは、一括インストーラーのAnacondaなどを用いてインストールしてあることを前提にします。インタラクティブ環境のJupyter Notebookも使用可能な状態にあることも前提です。

 自動車の自動運転などに応用されるCaffeやSegNetのような畳み込みニューラルネットワークを用いれば、1000種類以上の物体検出が可能ですが、OpenCVはディープラーニング機能を含んでいないので、そこまでの能力はありません。その代わり、構造はシンプルで、動作は非常に軽く、使いやすいです。iOSやAndroidなどをプラットホームとするモバイル機器でも利用できます。画像処理の初心者にも容易に使いこなせます。

Last updated: 2021.2.14



OpenCVのインストール


 Anacondaを前提にします。以下のようなコマンドを入力してインストールします。


$ pip install opencv-python

 インストールできたかどうかを見るために、


$ ipython

とPythonシェルを起動します。Ipythonが以下のように表示されますので、


Python 3.7.4 (default, Aug 13 2019, 15:17:50) 
Type 'copyright', 'credits' or 'license' for more information
IPython 7.19.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import cv2
In [2]: cv2.__version__
Out[3]: '4.1.1'

と入力して、cv2のバージョンが4.1.1であることを確認します。正常にインストールされています。


初歩的な画像処理


  OpenCVでの画像処理の初歩的コマンドは、画像を読む、画像を表示する、画像を保存する3種類の関数、cv2.imread(), cv2.imshow() , cv2.imwrite() です。 画像処理ライブラリでは、cv2.imreadメソッドを用いることで画像を読みみます。

書式は
img = cv2.imread(filename[,flag])

と入力します。ここで、filenameは読み込む画像のファイル名、flag=1ならoriginalのまま、0ならグレースケール、-1ならRGBの画像として読み込まれます。デフォルトはflag=1です。

 画像はNumPy配列(読み込んだ画像の画素値を格納)で、読み込みに対応している画像ファイル形式は、「jpg」「png」「bmp」「pgm」「pbm」「ppn」「dib」「jp2」「tiff」「tf」「ras」「sr」です。通常のNumPy配列と同様に、print関数で中身を確認できます。読み込み画像"flower.jpg"をワーキング・ディレクトリに保存して、Jupyter Notebookを起動して、以下のコードを入力してください。


import cv2
import numpy as np

img = cv2.imread("flower.jpg")
np.shape(img)
print (img)

 読み込まれた画像の配列次元と中身がndarrayで表示されます。

 この画像は、(300, 204, 3)次元配列なので、横300x縦204個のpixel(ピクセル)x3から構成されていることがわかる。ピクセルを画素とも言います。画像はカラーなので、RGB(赤・緑・青)の3色で表されるので、数字の 3 はこれを意味します。

 なので、各画素の値は3次元配列で保存されています。このように、1つの画素の色を、R(赤)、G(緑)、B(青)の3原色を混ぜ合わせて表現する画像をRGBカラー画像といいます。RGBカラー画像では、R, G, Bそれぞれの濃度を256階調(0~255 = 8bit)の整数値で表します。R, G, Bそれぞれの濃さを8bitで表現するため、1画素の色は24bit(=8bit×3色分)で表現されます。数値は(R, G, B)=(赤の濃度, 緑の濃度, 青の濃度)を表現します。画素の値は3色の3次元空間の点で表現されるので、3次元配列になります。

 画像を表示するために、


cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

と入力します。cv2.waitKey() はミリ秒単位でキーボードからの入力を待つという意味です。cv2.destroyAllWindows()は作成されたウインドウを消す命令文です。

 画像を保存するときは


cv2.imwrite('sunflower.png',img)

と入力します。第1引数は保存先のファイル名で、第2引数は読み込んだ画像名です。ワーキング・ディレクトリにsunflower.pngという画像ファイルが作成されます。作成された画像は

sunflwer.png

です。Matplotlibを用いて画像を表示する場合には、以下のように入力します。


from matplotlib import pyplot as plt

img = cv2.imread('flower.jpg',0)
plt.imshow(img, cmap = 'gray', interpolation = 'bicubic')
plt.xticks([]), plt.yticks([])  # to hide tick values on X and Y axis
plt.show()

このケースでは、imread()の第2引数が0になっているので、グレースケール(白黒画像)で読み込まれています。 なので、表示される画像は

greyflwer.png

となります。実は、matplotlibは、画像がRGBで入ってくることを期待しています。OpenCVで読み込んだ画像はBGR形式なので、そのままmatplotlibで表示するとおかしな画像になります。なので、カラーの順番を変換する必要があります。


cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

という変換文を挟む必要があります。

 次に、人物の顔や目の検出のサンプル・コードの作成について取り上げます。Haar Feature-based Cascade Classifiers を使用した物体検出が便利です。詳細は、opencv-python-tutorialsを参照ください。これらのOpenCVの検出用パッケージ(Haar-cascade Detection)は、opencv-python のインストール時に、 /opt/anaconda3/lib/python3.7/site-packages/cv2/data 以下のディレクトリに配置されます。以下のようなスクリプトを作成すると、写真(alumni2.jpg)から人物の顔の検出ができます。


import numpy as np
import cv2

cascade_path = "/Users/koichi/opt/anaconda3/lib/python3.7/site-packages/cv2/data/haarcascade_frontalface_alt.xml"

image = cv2.imread("alumni2.jpg")
color = (255,0,0)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cascade = cv2.CascadeClassifier(cascade_path)
facerect = cascade.detectMultiScale(gray, scaleFactor=1.3, 
                      minNeighbors =1,minSize=(1,1))
if len(facerect) > 0:
    for rect in facerect:
        cv2.rectangle(image, tuple(rect[0:2]),tuple(rect[0:2]+rect[2:4]),color,thickness=2)
else:
    print("no face")
cv2.imshow("detected.jpg",image)

cv2.waitKey()
cv2.destroyAllWindows()

読み込んだ画像をグレースケール画像に変換して、 detectMultiScale という検出プログラムにかけます。そのあと、 rectangle()というプログラムで読み込んだ画像の人物の顔を長方形の彩色枠で囲みます。結果画像は

detected1.png

detected2.png

となって、人物の顔が検出されています。画像の縮小率(scaleFactor)が結果に影響を与えます。値の大小により検出に間違いが起こります。縮小率の設定には試行錯誤が必要で、微妙です。


Web カメラからの画像をキャプチャーする


 Webカメラを映し出す方向に向けて設置して、usbコネクターをPCに接続してください。Jupyter Notebookを開いて、以下のpythonコードを作成してください。

#!/usr/bin/env python

import cv2

capture = cv2.VideoCapture(0)
if capture.isOpened() is False:
  raise IOError

while(True):
  try:
	ret, frame = capture.read()
	if ret is False:
	  raise IOError
	cv2.imshow('frame',frame)
	cv2.waitKey(1)
  except KeyboardInterrupt:
	# 終わるときは CTRL + C を押す
	break

capture.release()
cv2.destroyAllWindows()

capture = cv2.VideoCapture(0)とすると、PCに内臓のカメラからの映像になります。
  Jupyter Notebookで上記のスクリプトを実行すると、pythonの画像ウインドウとして、カメラからの映像が表示されます。表示の終了は[CTRL + C]キーの入力です。

 映像の保存は以下の通り行います。以下のコードをpythonスクリプトとして保存してください。

import numpy as np
import cv2

cap = cv2.VideoCapture(1)

# Define the codec and create VideoWriter object
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))

while(cap.isOpened()):
    ret, frame = cap.read()
    if ret==True:
        frame = cv2.flip(frame,1)

        # write the flipped frame
        out.write(frame)

        cv2.imshow('frame',frame)
        if cv2.waitKey(1) & 0xFF == ord('q'): # qキーで終了
            break
    else:
        break

# Release everything if job is finished
cap.release()
out.release()
cv2.destroyAllWindows()

fourcc = cv2.VideoWriter_fourcc(*'XVID')の代わりに、fourcc = cv2.VideoWriter_fourcc(*'MJPG')とすると容量が大きくなります。映像の表示ができますが、output.aviで保存された画像ファイルがMacでは読めません。

 Webカメラからの映像をキャプチャして、人物の顔や目を検出するプログラムを書いてみましょう。以下のコードをJupyter Notebookを用いて作成してください。

import numpy as np
import cv2


cap = cv2.VideoCapture(0)
if cap.isOpened() is False:
  raise IOError
  
face_cascade_path = "/Users/koichi/opt/anaconda3/lib/python3.7/site-packages/cv2/data/haarcascade_frontalface_default.xml"
eye_cascade_path = "/Users/koichi/opt/anaconda3/lib/python3.7/site-packages/cv2/data/haarcascades/haarcascade_eye.xml"

face_cascade = cv2.CascadeClassifier(face_cascade_path)
eye_cascade = cv2.CascadeClassifier(eye_cascade_path)


while True:
	ret, img = cap.read()
	gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
	faces = face_cascade.detectMultiScale(gray, 1.3, 5)
	for (x,y,w,h) in faces:
	  cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
	  roi_gray = gray[y:y+h, x:x+w]
	  roi_color = img[y:y+h, x:x+w]
#      eyes = eye_cascade.detectMultiScale(roi_gray)
#      for (ex,ey,ew,eh) in eyes:
#         cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)
	cv2.imshow('video image', img)
	key = cv2.waitKey(10)
	if key == 27:  # {CTRL+C}キーで終了
		break

cap.release()
cv2.destroyAllWindows()

 このコードを実行すると、カメラからの映像表示に、ブルーの顔枠が書き込まれます。検出の結果表示と映像の動きには若干のタイムラグが起こります。(グリーンの目の枠を表示させるようにすると、エラーが出ます。原因はわかりません。

Raspberry Pi で OpenCV のページへ行く