OpenCVで画像処理を試す
なんとなく画像認識系のプログラムに興味が湧いたところ、OpenCVを使えば簡単に試せるという話を聞いたので試してみました。
OpenCVとは?
画像処理・画像解析および機械学習等の機能を持つC/C++、Java、Python、MATLAB用ライブラリ。プラットフォームとしてmacOSやFreeBSD等全てのPOSIXに準拠したUnix系OS、Linux、Windows、Android、iOS等をサポートしている。
Wikipediaより引用:https://ja.wikipedia.org/wiki/OpenCV
準備
PC環境、言語
- Mac(Intel) Monterey 12.3.1
- Python 3.9.0
以下を使うのでインストール(コマンドそのまま)
- pip3 install numpy
- xcode-select –install
- brew install opencv
- pip3 install opencv-python
- pip install Pillow
参考サイト
- 基本準備
- ModuleNotFoundError: No module named ‘cv2’ が出た際に以下で解決
メジャーなオープンソースライブラリなのでググるとたくさん出てきます。
画像出してみる
import cv2
img = cv2.imread('/test.jpg')
cv2.imshow('テスト画像', img)
cv2.waitKey(1)
とりあえずこれで画像を表示できて環境構築の疲れを癒せます。
imread で画像を読み込み imshow で画像を表示できます。
超基本ですがOpenCVの馴染みやすさを一気に体感できたので後々これがめっちゃ大事だと思いました。
円の検出をしてみる
import numpy as np
img = cv2.imread('/test.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, dp=1, minDist=20, param1=100, param2=60, minRadius=5, maxRadius=0)
circles = np.uint16(np.around(circles))
for circle in circles[0, :]:
# 円周を描画する
cv2.circle(img, (circle[0], circle[1]), circle[2], (0, 165, 255), 5)
# 中心点を描画する
cv2.circle(img, (circle[0], circle[1]), 2, (0, 0, 255), 3)
cv2.imwrite("/test_circle.jpg", img)
img2 = cv2.medianBlur(img, 5)
cimg = cv2.cvtColor(img2, cv2.COLOR_GRAY2BGR)
circles = cv2.HoughCircles (img ,cv2.HOUGH_GRADIENT ,1 ,20, param1 = 500, param2 = 30, minRadius = 0, maxRadius = 0)
OpenCV初学で必ずと言っていいほど見かける「円の検出と描画」のプログラムです。
以下のサイトにサンプル画像も含めた詳細が載っています。
https://shikaku-mafia.com/cv2-houghcircles/
円の検出の HoughCircles や 円の描画の circle の引数もこちらのサイトの記述が参考になります。
また、何かを検出する際にグレースケール化( cvtColor に cv2.COLOR_BGR2GRAY を指定)はよく使われるので覚えておいた方がいいです。
グレースケールやカラー情報というもの自体が分からない場合は先にググっておくことを推奨します。
例:http://www.igunoss.co.jp/imageproc/imageproc1-2.html
カメラ読み込んでみる
import cv2
cap = cv2.VideoCapture(0)
while True:
# 1フレームずつ取得する。
ret, frame = cap.read()
#フレームが取得できなかった場合は、画面を閉じる
if not ret:
break
# ウィンドウに出力
cv2.imshow("Frame", frame)
key = cv2.waitKey(1)
# Escキーを入力されたら画面を閉じる
if key == 27:
break
cap.release()
cv2.destroyAllWindows()
VideoCapture という関数にで動画を読み込むことができて cv2.VideoCapture(‘/sample_video.mp4’) のように記述すれば動画を読み込ませることができますが、ここに 0 を指定すると備え付けのWEBカメラがキャプチャーできます。
カメラの読み込みには終わりがないので無限ループ内で1フレーム毎に取得してウィンドウに表示すればカメラ表示を再現できます。
ループさせなければ実行時の瞬間だけ取得されて実質写真なります。
顔を検出してみる
import cv2
face_cascade_path = '/usr/local/opt/opencv/share/opencv4/haarcascades/haarcascade_frontalface_default.xml'
eye_cascade_path = '/usr/local/opt/opencv/share/opencv4/haarcascades/haarcascade_eye.xml'
face_cascade = cv2.CascadeClassifier(face_cascade_path)
eye_cascade = cv2.CascadeClassifier(eye_cascade_path)
cap = cv2.VideoCapture(0)
while True:
ret, img = cap.read()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.3, minNeighbors=5)
for x, y, w, h in faces:
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
face = img[y: y + h, x: x + w]
face_gray = gray[y: y + h, x: x + w]
eyes = eye_cascade.detectMultiScale(face_gray)
for (ex, ey, ew, eh) in eyes:
cv2.rectangle(face, (ex, ey), (ex + ew, ey + eh), (0, 255, 0), 2)
cv2.imshow('video image', img)
key = cv2.waitKey(10)
if key == 27: # ESCキーで終了
break
cap.release()
cv2.destroyAllWindows()
カメラ内に顔が写ったら検知します。これぞ画像認識って感じがしますね。
メガネや正面など検知方法を変える場合は face_cascade_path を別のテンプレート(カスケード型の識別器とかカスケード型の分類器とか呼ばれてます。情報の集合体のようなもの?)に変更してください。
このファイルの絶対パスが opencv4 ではなく opencv だったりと微妙に環境によって違いがあるので注意してください。
これらファイルがそれぞれ何を検知するのに使えるのかは以下の記事が綺麗にまとめてくれてました。
https://qiita.com/tnoce/items/c819c85a85c16d246be8#カスケード型の識別器のファイル
デフォルトで入っている分類機のファイルはOpenCVが用意したものですが、これを自作することも可能です。
参考 https://www.pc-koubou.jp/magazine/21280
感想
まだ超基本的な機能に触れた程度ですが、先人達の記事により想像よりも遥かに簡単に扱えました。
なんなら環境構築段階が一番大変までありました。
しかし描画の関数などの計算はかなり面倒なのでそこら辺を自力でやっていたらかなり時間がかかりそうでした。
ちなみに文字抽出やテンプレートマッチングなど面白いことが出来そうな機能がまだまだあるので気が向いたら続きを書こうと思います。
あわよくば何かアプリでも作れたら楽しそうですね。
コメントを残す