OpenCV 3.4.1で背景差分

背景差分

f:id:whoopsidaisies:20180301131807p:plain

画像の前景と背景を分離する手法。2013年にOpenCV 2.4.7での背景差分の記事を書いたが、2018年になったいまOpenCV 3.4.1で背景差分を行おうとしたら使えるアルゴリズムが増えていたのでまとめておく。

アルゴリズム

MOG, MOG2, GMG

OpenCV 2.4.7でも使えた。以下のページに日本語でわかりやすい説明がある。

背景差分 — OpenCV-Python Tutorials

KNN

K近傍方に基づく背景差分。前景の画素数が少ない場合は効率が良いらしい。

Efficient adaptive density estimation per image pixel for the task of background subtraction - ScienceDirect

CNT

低スペックな計算機でもほかのアルゴリズムより高速に処理ができる。CNTという名前は「CouNT」の省略らしい。Raspberry Pi3でのベンチマークではMOG2が41秒に対し、CNTは18秒。

https://sagi-z.github.io/BackgroundSubtractorCNT/

LSBP

Local SVG Binary Pattern。注目画素とその周辺画素の大小関係を符号化するLBP(Local Binary Pattern)は、高速に計算可能な画像特徴量として知られている。局所的なノイズや隣接画素が類似しているような場合にもロバストにするようにSVD(特異値分解)を使った特徴量で背景差分を行っているそう。ちゃんと勉強してないのでよくわらからない。

https://www.cv-foundation.org/openaccess/content_cvpr_2016_workshops/w24/papers/Guo_Background_Subtraction_Using_CVPR_2016_paper.pdf

GSOC

LSBP特徴を使ってる。ノイズ除去とか穴埋めといった後処理をしているらしい。GSOC(Google Summer of Code)2017中で開発されたとかで元論文等はないらしいのでソースコードを読もう。

opencv_contrib/bgfg_gsoc.cpp at 6520dbaa224a661ca8105b1ab0b71451fd715f4c · opencv/opencv_contrib · GitHub

コード

実行にはopencv_contribが必要。

C++

opencv_contribをダウンロードし、opencvcmake時に例えば以下のようにOPENCV_EXTRA_MODULES_PATHオプションを指定してビルドする。

$ cmake -DOPENCV_EXTRA_MODULES_PATH=<opencv_contrib>/modules -DBUILD_opencv_legacy=OFF <opencv_source_directory>

ソースコード

#include <opencv2/opencv.hpp>
#include <opencv2/core/utility.hpp>
#include <opencv2/bgsegm.hpp>

int main()
{
    // 動画ファイルの読み込み
    cv::VideoCapture cap = cv::VideoCapture("video.mp4");
    // 背景差分器の生成
    cv::Ptr<cv::BackgroundSubtractor> bgfs = cv::bgsegm::createBackgroundSubtractorGSOC();
    //cv::Ptr<cv::BackgroundSubtractor> bgfs = cv::bgsegm::createBackgroundSubtractorCNT();
    //cv::Ptr<cv::BackgroundSubtractor> bgfs = cv::bgsegm::createBackgroundSubtractorGMG();
    //cv::Ptr<cv::BackgroundSubtractor> bgfs = cv::bgsegm::createBackgroundSubtractorLSBP();
    //cv::Ptr<cv::BackgroundSubtractor> bgfs = cv::bgsegm::createBackgroundSubtractorMOG();
    //cv::Ptr<cv::BackgroundSubtractor> bgfs = cv::createBackgroundSubtractorMOG2();
    //cv::Ptr<cv::BackgroundSubtractor> bgfs = cv::createBackgroundSubtractorKNN();

    while (cv::waitKey(1) == -1)
    {
        cv::Mat frame, foreGroundMask, segm;

        cap >> frame;
        if (frame.empty())
            break;

        bgfs->apply(frame, foreGroundMask);
        frame.convertTo(segm, 0, 0.5);
        cv::add(frame, cv::Scalar(100, 100, 0), segm, foreGroundMask);
    
        cv::imshow("output", segm);
    }
    return 0;
}

Python

pipで管理している場合、以下のようにopencv-pythonをアンインストール後にopencv-contrib-pythonをインストールすればopencv_contribが使える。

pip uninstall opencv-python
pip install opencv-contrib-python

ソースコード

import cv2

cap = cv2.VideoCapture('video.mp4')
bgs = cv2.bgsegm.createBackgroundSubtractorLSBP()

while(cap.isOpened()):
    ret, frame = cap.read()
    mask = bgs.apply(frame)
    bg = bgs.getBackgroundImage()
    cv2.imshow('mask', mask)
    cv2.imshow('bg', bg)
    if cv2.waitKey(1) != -1:
        break

cap.release()
cv2.destroyAllWindows()

適用結果

比較のために各アルゴリズムを並べてみた。パラメータ調整もしてないから比較もくそもない気はするけど。GSOCが綺麗。LSBPはあんまり

www.youtube.com

あと、背景差分やるだけだったらたぶん以下のページで紹介されているBGSLibraryを使ったほうが良さそうではある。

blog.negativemind.com