私たちのプロジェクトの1つでも同じタスクがありました。
背景モデルを取得するには、クラスBackgroundModelを作成し、最初の(たとえば)50フレームをキャプチャし、平均フレームを計算して、背景モデルのピクセルエラーを回避します。
たとえば、カメラから8ビットのグレースケール画像(CV_8UC1)を取得する場合は、クリッピングを回避するためにモデルをCV_16UC1で初期化します。
cv::Mat model = cv::Mat(HEIGHT, WIDTH, CV_16UC1, cv::Scalar(0));
ここで、最初のフレームがモデルを計算するのを待って、すべてのフレームをモデルに追加し、受信したフレームの量を数えます。
void addFrame(cv::Mat frame) {
cv::Mat convertedFrame;
frame.convertTo(convertedFrame, CV_16UC1);
cv::add(convertedFrame, model, model);
if (++learnedFrames >= FRAMES_TO_LEAN) { // FRAMES_TO_LEARN = 50
createMask();
}
}
createMask()関数は、モデルに使用する平均フレームを計算します。
void createMask() {
cv::convertScaleAbs(model, mask, 1.0 / learnedFrames);
mask.convertTo(mask, CV_8UC1);
}
これで、すべてのフレームをBackgroundModelクラスを介して関数subtract()に送信するだけです。結果が空のcv::Matの場合でも、マスクは計算されます。それ以外の場合は、減算されたフレームを取得します。
cv::Mat subtract(cv::Mat frame) {
cv::Mat result;
if (++learnedFrames >= FRAMES_TO_LEAN) { // FRAMES_TO_LEARN = 50
cv::subtract(frame, mask, result);
}
else {
addFrame(frame);
}
return result;
}
最後になりましたが、Scalar sum(const Mat&mtx)を使用してピクセルの合計を計算し、ライトが点灯しているフレームかどうかを判断できます。