画像処理の復習
引き続き、大学でIoTのリカレント教育に出ています。
講義では「生産現場の技術者向け」を対象としているので、コンピュータの技術面についてあまり深いところに突っ込みません。
先日の画像処理の演習でも、プログラミングすると言うよりは与えられたコードをただ実行して体験するものでした。
身につけるためにも自宅で実際に調べながら作ってみました。 講義ではRaspberry Piを使っていましたが、Raspberry Pi用のカメラを繋ぐのが面倒なので、実行環境はWindows PCで、カメラは市販のWebカメラを使用しました。 言語はPython、画像処理ライブラリはOpenCV2を使っています。
背景差分
背景との差分を取り、動きのあった場所を検出します。
createBackgroundSubtractorMOG2
で生成されるオブジェクトを使うだけで、考えて作るとことは殆どありません。その他の有名なアルゴリズムも呼び出すだけで使えるようです。
from cv2 import cv2 cap = cv2.VideoCapture(0) fgbg = cv2.createBackgroundSubtractorMOG2() while True: ret, frame = cap.read() cv2.imshow('', fgbg.apply(frame)) k = cv2.waitKey(1) if k==27: break cap.release() cv2.destroyAllWindows()
こんな感じ。ものを動かすと白くなり、差分が検知されているのがわかります。
円・直線検出
円や直線のような画像に赤色でマーキングします。
こちらも検出自体はHoughCircles
とHoughLines
が全部やってくれます。
from cv2 import cv2 import math import numpy as np cap = cv2.VideoCapture(0) fgbg = cv2.createBackgroundSubtractorMOG2() def mask_circle(img): height, width = img.shape[:2] mask_color = (0,0,255) # グレイスケールに変換 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 円検出 circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, dp=1, minDist=50, param1=120, param2=40, minRadius=40, maxRadius=100) # 255で埋まった3次元配列(縦x横xRGB3次元)を生成 mask = np.full((height, width, 3), 255, np.uint8) if circles is not None: for cs in circles: for c in cs: mask = cv2.bitwise_or(mask, cv2.circle(mask, (c[0], c[1]), 80, mask_color, 20)) return mask def mask_line(img): height, width = img.shape[:2] mask_color = (0, 0, 255) # グレイスケールに変換 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) gray = cv2.Canny(gray, 50, 150, apertureSize=3) # 円検出 lines = cv2.HoughLines(gray, 1, np.pi/180, 200) # 255で埋まった3次元配列(縦x横xRGB3次元)を生成 mask = np.full((height, width, 3), 255, np.uint8) if lines is not None: for rho, theta in lines[0]: x1 = int(np.cos(theta)*rho - 1000*np.sin(theta)) y1 = int(np.sin(theta)*rho + 1000*np.cos(theta)) x2 = int(np.cos(theta)*rho + 1000*np.sin(theta)) y2 = int(np.sin(theta)*rho - 1000*np.cos(theta)) mask = cv2.bitwise_or(mask, cv2.line(mask, (x1, y1), (x2, y2), mask_color, 2)) return mask mask_types = [('circle', mask_circle), ('line', mask_line)] selection = 0 while True: width = 640 height = 480 ret, frame = cap.read() img = cv2.resize(frame, (width, height)) if mask_types[selection][1] is not None: mask = mask_types[selection][1](frame) masked_img = cv2.bitwise_and(img, mask) img_with_text = cv2.putText(masked_img, mask_types[selection][0], (0, 30), 0, 1, (255, 255, 255)) cv2.imshow('masked', img_with_text) k = cv2.waitKey(1) if k == 27: break elif k == ord('z'): selection = (selection - 1) % len(mask_types) cap.release() cv2.destroyAllWindows()
こんな感じ。円と線が検知されています。
まとめ
OpenCV2はプリセットが充実していて、サクッと作るだけなら簡単にできます。いかに精度を上げるか、分析結果をどう表現するか、今後も勉強していきます。