現在、ビデオ監視に基づく侵入システムに取り組んでいます。このタスクを完了するために、シーンの背景のスナップショットを撮ります(完全にクリーンで、人や動いている物体がないと仮定します)。次に、(静的)ビデオカメラから取得したフレームを比較し、違いを探します。私は、人間の形など何でもany違いをチェックできる必要があるので、特定の特徴抽出ができません。
通常、私は持っています:
私はOpenCVを使用しているので、比較するために基本的に次のことを行います。
_cv::Mat bg_frame;
cv::Mat cam_frame;
cv::Mat motion;
cv::absdiff(bg_frame, cam_frame, motion);
cv::threshold(motion, motion, 80, 255, cv::THRESH_BINARY);
cv::erode(motion, motion, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3,3)));
_
結果は次のとおりです。
ご覧のように、腕は剥がされています(色差の競合が原因だと思います)。これは悲しいことに私が望むものではありません。
私はcv::Canny()
の使用を追加して、エッジを検出し、腕の欠けている部分を埋めることを考えましたが、悲しいことに(もう一度)、ほとんどの場合ではない状況で問題を解決します。
正確な差分レポートを取得するために使用できるアルゴリズムまたは手法はありますか?
PS:画像、すみません。新しく加入したため、十分な評判がありません。
[〜#〜] edit [〜#〜]ここではグレースケール画像を使用しますが、どのような解決策も受け入れています。
コードの問題の1つは_cv::threshold
_で、これは1つのチャネルイメージのみを使用します。グレースケールのみで2つの画像間のピクセル単位の「差」を見つけると、多くの場合、直感に反する結果につながります。
提供された画像が少し翻訳されているか、カメラが静止していないため、背景画像を操作して前景を追加しました。
背景画像:
前景画像:
コード:
_ cv::Mat diffImage;
cv::absdiff(backgroundImage, currentImage, diffImage);
cv::Mat foregroundMask = cv::Mat::zeros(diffImage.rows, diffImage.cols, CV_8UC1);
float threshold = 30.0f;
float dist;
for(int j=0; j<diffImage.rows; ++j)
for(int i=0; i<diffImage.cols; ++i)
{
cv::Vec3b pix = diffImage.at<cv::Vec3b>(j,i);
dist = (pix[0]*pix[0] + pix[1]*pix[1] + pix[2]*pix[2]);
dist = sqrt(dist);
if(dist>threshold)
{
foregroundMask.at<unsigned char>(j,i) = 255;
}
}
_
この結果を与える:
この違いの画像:
一般に、ピクセル単位の差分解釈から完全な前景/背景セグメンテーションを計算することは困難です。
フォアグラウンドマスクから開始する実際のセグメンテーションを取得するために、おそらく後処理のものを追加する必要があります。安定したユニバーサルソリューションがあるかどうかはまだわかりません。
Berakが述べたように、実際には単一の背景画像を使用するだけでは十分ではないため、時間の経過とともに背景画像を計算/管理する必要があります。このトピックをカバーする論文はたくさんありますが、安定した普遍的な解決策はまだありません。
ここにいくつかのテストがあります。 HSV
色空間:cv::cvtColor(backgroundImage, HSVbackgroundImagebg, CV_BGR2HSV); cv::cvtColor(currentImage, HSV_currentImage, CV_BGR2HSV);
に変換し、この空間で同じ操作を実行して、次の結果を得ました。
入力にノイズを追加した後:
私はこの結果を得ます:
そのため、しきい値が少し高すぎる可能性があります。 HSV色空間もご覧になることをお勧めしますが、「差分画像」を再解釈し、各チャネルを再スケーリングして差分値を結合する必要がある場合があります。
私はPythonを使用していますが、これは私の結果です:
コード:
# 2017.12.22 15:48:03 CST
# 2017.12.22 16:00:14 CST
import cv2
import numpy as np
img1 = cv2.imread("img1.png")
img2 = cv2.imread("img2.png")
diff = cv2.absdiff(img1, img2))
mask = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY)
th = 1
imask = mask>th
canvas = np.zeros_like(img2, np.uint8)
canvas[imask] = img2[imask]
cv2.imwrite("result.png", canvas)
更新、ここにC++コードがあります:
//! 2017.12.22 17:05:18 CST
//! 2017.12.22 17:22:32 CST
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main() {
Mat img1 = imread("img3_1.png");
Mat img2 = imread("img3_2.png");
// calc the difference
Mat diff;
absdiff(img1, img2, diff);
// Get the mask if difference greater than th
int th = 10; // 0
Mat mask(img1.size(), CV_8UC1);
for(int j=0; j<diff.rows; ++j) {
for(int i=0; i<diff.cols; ++i){
cv::Vec3b pix = diff.at<cv::Vec3b>(j,i);
int val = (pix[0] + pix[1] + pix[2]);
if(val>th){
mask.at<unsigned char>(j,i) = 255;
}
}
}
// get the foreground
Mat res;
bitwise_and(img2, img2, res, mask);
// display
imshow("res", res);
waitKey();
return 0;
}
同様の回答:
これは、バックグラウンド減算と呼ばれるよく知られた古典的なコンピュータビジョンの問題です。この問題を解決するために使用できる多くのアプローチがあり、それらのほとんどは既に実装されているので、まず複数の既存のアルゴリズムを見てみる必要があると思います。ここにそれらのほとんどのオープンソース実装があります: https:/ /github.com/andrewssobral/bgslibrary (私は個人的にSUBSENSEが最良の結果を提供していることを発見しましたが、非常に遅いです)