LoginSignup
4
4

More than 3 years have passed since last update.

OpenCVで生活の乱れを採点してみた

Last updated at Posted at 2020-01-27

はじめに

生活の乱れを採点することで、生活改善につなげたいと思います。
この頃、部屋の片付けが面倒になってきたので、
部屋に設置したカメラの映像から、部屋の汚さをリアルタイム採点してみました。

作ったもの

汚部屋メーター
obeya.movie.gif

  • 左上の数字:汚部屋スコア
    • 点数が高いほど汚い
  • 左上の英字:3段階判定
    • [CLEAN] きれい
    • [MESSY] 散らかっている
    • [OBEYA] 汚部屋
  • 緑色の線
    • 散らかっている場所

使ったもの

  • Python 3.5.4
  • OpenCV 4.1.1.26
  • MacOS 10.14.6
  • USBカメラ ELECOM UCAM-C310FBBK

処理フロー

1. 画像処理

obeya_pic4.png 1-1. カメラからフレームを読み込みます。
参考:動画を扱う — OpenCV-Python Tutorials 1 documentation
obeya_pic3.png 1-2. グレースケールに変換します。
cv2.cvtColor()
obeya_pic2.png 1-3. Canny法によるエッジ検出を行います。輪郭線を強調した画像が取得できます。
cv2.Canny()

2. ベクトル・数値処理

2-1. 輪郭線の抽出

1-3 の画像から、cv2.findContours()で輪郭線のベクトルデータを取得します。

2-2. ちょうどよい長さの輪郭線を選別

2-1で取得したベクトルを for 文に突っ込むと、輪郭線1本分のデータが得られるので、cv2.arcLength()を使って輪郭線の長さを取得します。
長すぎる、または短すぎる輪郭線は捨てちゃいます。

2-3. スコアの集計

2-2で得られた輪郭線の長さを単純に足し算して、点数を計算します。

3. 完成

最後に、1-1 で読み込んだ元の画像、2-2で選別された輪郭線、2-3で計算したスコアなどを重ね合わせて出力すれば完成です。
obeya_pic.png

ソースコード


import cv2
import numpy as np
import math
from collections import deque
from statistics import  median

FONT = cv2.FONT_HERSHEY_SIMPLEX
RED = (0, 0, 255)
GREEN = (0, 255, 0)
BLUE = (255, 0, 0)
ORANGE = (0, 130, 255)
SCORE_AP = (0, 80)
SCORE_FONT_SIZE = 2
SCORE_FONT_WEIGHT = 8

score_queue = deque([])


def get_score_summary(total_arc_length):
    score_queue.append(math.floor(total_arc_length / 100))
    if len(score_queue) > 30:
        score_queue.popleft()

    score = median(score_queue)

    if score > 200:
        return score, '[OBEYA]', RED
    elif score > 150:
        return score, '[MESSY]', ORANGE
    else:
        return score, '[CLEAN]', BLUE


def is_obeya_contour(arc_length):
    return 100 < arc_length < 900


def show_obeya_score(frame):
    score_frame = frame.copy()

    gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    canny_frame = cv2.Canny(gray_frame, 120, 200)
    contours, hierarchy = cv2.findContours(canny_frame, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE )

    total_arc_length = 0
    for contour in contours:
        arc_length = cv2.arcLength(contour, True)
        if is_obeya_contour(arc_length):
            cv2.drawContours(score_frame, contour, -1, GREEN, 3)
            total_arc_length += arc_length

    score, decision, color = get_score_summary(total_arc_length)
    cv2.putText(score_frame, ' '.join([str(score), decision]),
            SCORE_AP, FONT, SCORE_FONT_SIZE, color, SCORE_FONT_WEIGHT, cv2.LINE_AA)

    cv2.imshow('frame: contour', score_frame)


if __name__ == '__main__':
    cap = cv2.VideoCapture(0)
    while(True):
        ret, frame = cap.read()
        show_obeya_score(frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    cap.release()
    cv2.destroyAllWindows()

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4