關於幀差法的想法(opencv)

幀差法

幀差法,顧名思義就是將視頻中前後兩幀做減法,當前幀在(x,y)點處的像素值減去上一幀在(x,y)處的像素值。該方法的優點是提取效果比較穩定,速度比較快。缺點也是蠻明顯的,如果你要提取的目標是靜止的或者移動速度很慢,前後兩幀的前景物體會有很大一部分重合,從而會導致提取出來的圖像有空洞。

當我們要提取前景時,幀差法基本上是最簡單的一種方法了,變化緩慢的背景,以及運動較快的物體,在進行幀差法之後,進行閾值分割,將差值圖像變成二值圖像,就完成了運動目標以及背景的分離。

本文主要講一下最簡單的幀差,三幀差法原理相差不大,對稱差分就不講了。
公式如下:
在這裏插入圖片描述

示例

我簡單編寫了一個幀差法及閾值分割的程序如下:

#include <opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
	VideoCapture capture("F://crop.avi");
	//VideoCapture capture(0);//直接調用攝像頭
	if (!capture.isOpened())
	{
		cout << "data error" << endl;
		return false;
	}//測試數據是否讀入
	Mat temp, pre, current, result;
	Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));//結構元素
	Mat image1, image2;
	Mat After_midfiler;
	//Mat bsmaskMOG2;
	int num = 0;
	///Ptr<BackgroundSubtractor> pMOG2 = createBackgroundSubtractorMOG2();
	while (1)
	{
		capture >> temp;
		imshow("show", temp);
		//------------------------------------------
		++num;
		//pMOG2->apply(temp, bsmaskMOG2);
		if (num == 1)
		{
			//BackgroundSubtractorMOG2::getBackgroundImage();
			cvtColor(temp, pre, COLOR_BGR2GRAY);

		}
		if (num > 1)
		{
			cvtColor(temp, current, COLOR_BGR2GRAY);
			absdiff(pre, current, result);//用幀差法求前景
			imshow("【背景】", pre);
			imshow("【幀差】", result);
			threshold(result, result, 60, 255, 0);
			imshow("【閾值分割後】", result);
			medianBlur(result, After_midfiler, 3);     //中值濾波法
			imshow("After_midfiler", After_midfiler);
			morphologyEx(After_midfiler, image1, MORPH_OPEN, element);
			morphologyEx(image1, image2, MORPH_CLOSE, element);
			imshow("image2", image2);
			char c = waitKey(30);
			if (c == 27)
				break;
			cvtColor(temp, pre, COLOR_BGR2GRAY);
			
		}
	}
}


這裏只放上原視頻截圖以及幀差的結果
在這裏插入圖片描述
在這裏插入圖片描述
由於魚的遊動十分緩慢,幀差的結果並不理想。

優化嘗試1

當運動物體變化很慢時,前面已經說過幀差會產生空洞,再進行閾值分割,這些部分會被當做背景處理。思考了一下,每一幀的變化很慢,但是總是會有變化的,如果將這每一幀與第一幀進行差分會有什麼結果?
(註釋掉代碼cvtColor(temp, pre, COLOR_BGR2GRAY);即可)
嘗試的運行結果如下:
在這裏插入圖片描述
這裏的結果明顯清晰了許多,因爲後面魚的位置與第一幀相比有了很大的區別,然而這裏的問題是,第一幀中的魚乾擾了結果,本來只有兩條,幀差之後變成了四條。

優化嘗試2

再上面的基礎上進行優化,思路是想辦法將第一幀中的魚去掉,只留下魚缸。也就是嘗試進行簡單的背景建模。
我的具體做法是,將當前每一幀與第一幀進行逐個像素的對比,由於魚的遊動,每一像素點都會存在沒有魚的時刻,想辦法將這些不同時刻的像素點整合到一幀裏就可以。我用的代碼如下:

for (int i = 0;i < current.rows;i++)
			{
				uchar *p = current.ptr<uchar>(i);
				uchar *q = pre.ptr<uchar>(i);
				for (int j = 0;j < current.cols;j++)
				{
					if (q[j] < p[j])
						q[j] = p[j];
				}
			}

運行效果如下:
在這裏插入圖片描述結果較爲喜人,但是這個建模需要一定的時間,並且建模過程中會受到光照的影響。通過遍歷,會把光照增加的部分添加到背景之中。

——————————————————————————————
分割線,後續針對幀差法的優化措施待更新~~~~~~~~~~~~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章