欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

OpenCV4 實現背景分離的詳細步驟(背景減法模型)

 更新時間:2021年09月16日 14:47:23   作者:RayChiu757374816  
背景分離(BS)是一種通過使用靜態(tài)相機來生成前景掩碼(即包含屬于場景中的移動對象像素的二進制圖像)的常用技術,本文給大家介紹OpenCV4 實現背景分離的詳細步驟,需要的朋友可以參考下

定義:

背景分離,又稱背景減法模型。

背景分離(BS)是一種通過使用靜態(tài)相機來生成前景掩碼(即包含屬于場景中的移動對象像素的二進制圖像)的常用技術。

顧名思義,BS計算前景掩碼,在當前幀與背景模型之間執(zhí)行減法運算,其中包含場景的靜態(tài)部分,或者更一般而言,考慮到所觀察場景的特征,可以將其視為背景的所有內容。

背景建模包括兩個主要步驟:

1. 背景初始化;

2. 背景更新。

初步,計算背景的初始模型,而在第二步中,更新模型以適應場景中可能的變化。

OpenCV中三個背景分離的重要函數

BackgroundSubtractorMOG()

這是一個以混合高斯模型為基礎的前景/背景分割算法。

它使用 K(K=3 或 5)個高斯分布混合對背景像素進行建模。使用這些顏色(在整個視頻中)存在時間的長短作為混合的權重。背景的顏色一般持續(xù)的時間最長,而且更加靜止。

在 x,y平面上一個像素就是一個像素,沒有分布,但是背景建模是基于時間序列的,因此每一個像素點所在的位置在整個時間序列中就會有很多值,從而構成一個分布

使用函數時先用函數:CV2.createBackgroundSubtractorMOG() 創(chuàng)建一個背景對象。這個函數有些可選參數,比如要進行建模場景的時間長度,高斯混合成分的數量,閾值等。將他們全部設置為默認值。然后在整個視頻中我們是需要使用backgroundsubtractor.apply() 就可得到前景的掩模了,移動的物體會被標記為白色,背景會被標記為黑色的,前景的掩模就是白色的了。

不過目前這個方法已經被棄用了,OpenCV中也沒有了相關函數的API。

BackgroundSubtractorMOG2

這個也是以高斯混合模型為基礎的背景/前景分割算法。這個算法的一個特點是它為每 一個像素選擇一個合適數目的高斯分布。(上一個方法中我們使用是 K 高斯分布),這樣就會對由于亮度等發(fā)生變化引起的場景變化產生更好的適應。

和前面一樣我們需要創(chuàng)建一個背景對象。但在這里我們我們可以選擇是否檢測陰影。如果 detectShadows = True(默認值),它就會檢測并將影子標記出來,但是這樣做會降低處理速度。影子會被標記為灰色。

BackgroundSubtractorMOG2算法的兩個改進點:

  1.  -陰影檢測
  2. -速度快了一倍

BackgroundSubtractorGMG

此算法結合了靜態(tài)背景圖像估計和每個像素的貝葉斯分割。它使用前面很少的圖像(默認為前 120 幀)進行背景建模。使用了概率前景估計算法(使用貝葉斯估計鑒定前景)。這是一種自適應的估計,新觀察到的 對象比舊的對象具有更高的權重,從而對光照變化產生適應。一些形態(tài)學操作 如開運算閉運算等被用來除去不需要的噪音,在前幾幀圖像中你會得到一個黑色窗口,對結果進行形態(tài)學開運算對與去除噪聲很有幫助。

不過同樣的,這個方法目前也是不再用了。

BackgroundSubtractorKNN

KNN作為大名鼎鼎的機器學習算法,其用在背景分離應用中也是得心應手,但是在此不對KNN作過多的解釋。

C++實現:

#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include <opencv2/highgui.hpp>
#include <opencv2/video.hpp>
#include <iostream>
#include <sstream>
using namespace cv;
using namespace std;
 
const int HISTORY_NUM = 7;// 14;// 歷史信息幀數
const int nKNN = 3;// KNN聚類后判斷為背景的閾值
const float defaultDist2Threshold = 20.0f;// 灰度聚類閾值
 
struct PixelHistory
{
	unsigned char* gray;// 歷史灰度值
	unsigned char* IsBG;// 對應灰度值的前景/背景判斷,1代表判斷為背景,0代表判斷為前景
};
 
 
int main()
{
	PixelHistory* framePixelHistory = NULL;// 記錄一幀圖像中每個像素點的歷史信息
	cv::Mat frame, FGMask, FGMask_KNN;
	int keyboard = 0;
	int rows, cols;
	rows = cols = 0;
	bool InitFlag = false;
	int frameCnt = 0;
	int gray = 0;
	VideoCapture capture("768X576.avi");
	Ptr<BackgroundSubtractorKNN> pBackgroundKnn =
		createBackgroundSubtractorKNN();
	pBackgroundKnn->setHistory(200);
	pBackgroundKnn->setDist2Threshold(600);
	pBackgroundKnn->setShadowThreshold(0.5);
 
	while ((char)keyboard != 'q' && (char)keyboard != 27)
	{
		// 讀取當前幀
		if (!capture.read(frame))
			exit(EXIT_FAILURE);
 
		cvtColor(frame, frame, COLOR_BGR2GRAY);
		if (!InitFlag)
		{
			// 初始化一些變量
			rows = frame.rows;
			cols = frame.cols;
			FGMask.create(rows, cols, CV_8UC1);// 輸出圖像初始化
 
			// framePixelHistory分配空間
			framePixelHistory = (PixelHistory*)malloc(rows * cols * sizeof(PixelHistory));
			for (int i = 0; i < rows * cols; i++)
			{
				framePixelHistory[i].gray = (unsigned char*)malloc(HISTORY_NUM * sizeof(unsigned char));
				framePixelHistory[i].IsBG = (unsigned char*)malloc(HISTORY_NUM * sizeof(unsigned char));
				memset(framePixelHistory[i].gray, 0, HISTORY_NUM * sizeof(unsigned char));
				memset(framePixelHistory[i].IsBG, 0, HISTORY_NUM * sizeof(unsigned char));
			}
 
			InitFlag = true;
		}
		if (InitFlag)
		{
			FGMask.setTo(Scalar(255));
			for (int i = 0; i < rows; i++)
			{
				for (int j = 0; j < cols; j++)
				{
					gray = frame.at<unsigned char>(i, j);
					int fit = 0;
					int fit_bg = 0;
					// 比較確定前景/背景
					for (int n = 0; n < HISTORY_NUM; n++)
					{
						if (fabs(gray - framePixelHistory[i * cols + j].gray[n]) < defaultDist2Threshold)// 灰度差別是否位于設定閾值內
						{
							fit++;
							if (framePixelHistory[i * cols + j].IsBG[n])// 歷史信息對應點之前被判斷為背景
							{
								fit_bg++;
							}
						}
					}
					if (fit_bg >= nKNN)// 當前點判斷為背景
					{
						FGMask.at<unsigned char>(i, j) = 0;
					}
					// 更新歷史值
					int index = frameCnt % HISTORY_NUM;
					framePixelHistory[i * cols + j].gray[index] = gray;
					framePixelHistory[i * cols + j].IsBG[index] = fit >= nKNN ? 1 : 0;// 當前點作為背景點存入歷史信息
 
				}
			}
		}
 
		pBackgroundKnn->apply(frame, FGMask_KNN);
		imshow("Frame", frame);
		imshow("FGMask", FGMask);
		imshow("FGMask_KNN", FGMask_KNN);
 
		keyboard = waitKey(30);
		frameCnt++;
	}
	capture.release();
 
	return 0;
 
}

python實現:

import cv2
 
cap=cv2.VideoCapture('./768x576.avi')
 
fgbg = cv2.createBackgroundSubtractorKNN()
 
while (1):
    ret, frame = cap.read()
 
    fgmask = fgbg.apply(frame)
 
    cv2.imshow('frame', fgmask)
    k = cv2.waitKey(100) & 0xff
    if k == 27:
        break
 
cap.release()
cv2.destroyAllWindows()

利用圖像減法函數實現(python版本):

import cv2
import time
"""
背景減法
"""
cap = cv2.VideoCapture("./768x576.avi")
 
_, first_frame = cap.read()
first_gray = cv2.cvtColor(first_frame, cv2.COLOR_BGR2GRAY)
first_gray = cv2.GaussianBlur(first_gray, (5, 5), 0)
cv2.imshow("First frame", first_frame)
cv2.imwrite('first_frame.jpg', first_frame)
 
count_frame = 0
start = time.time()
 
while True:
    count_frame += 1
    _, frame = cap.read()
    gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    gray_frame = cv2.GaussianBlur(gray_frame, (5, 5), 0)
 
    difference = cv2.absdiff(first_gray, gray_frame)
    _, difference = cv2.threshold(difference, 25, 255, cv2.THRESH_BINARY)
 
    cv2.imshow("Frame", frame)
    cv2.imshow("difference", difference)
 
    key = cv2.waitKey(30)
    if key == 27:
        break
 
    end = time.time()
    print("time %.2f s" % (end-start))
    print(count_frame)
 
cap.release()
cv2.destroyAllWindows()

到此這篇關于OpenCV4 實現背景分離、背景減法模型的文章就介紹到這了,更多相關OpenCV4 實現背景分離內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 簡述C語言中system()函數與vfork()函數的使用方法

    簡述C語言中system()函數與vfork()函數的使用方法

    這篇文章主要介紹了簡述C語言中system()函數與vfork()函數的使用方法,是C語言入門學習中的基礎知識,需要的朋友可以參考下
    2015-08-08
  • C語言進階:指針的進階(3)

    C語言進階:指針的進階(3)

    這篇文章主要介紹了C語言指針詳解及用法示例,介紹了其相關概念,然后分享了幾種用法,具有一定參考價值。需要的朋友可以了解下
    2021-09-09
  • C++?LeetCode1827題解最少操作使數組遞增

    C++?LeetCode1827題解最少操作使數組遞增

    這篇文章主要為大家介紹了C++?LeetCode1827題解最少操作使數組遞增示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • C語言鏈接屬性的實踐應用

    C語言鏈接屬性的實踐應用

    C語言中鏈接屬性決定如何處理在不同文件中出現的標示符,下面這篇文章主要給大家介紹了關于C語言鏈接屬性的實踐應用,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-03-03
  • C語言控制進程之進程等待詳解

    C語言控制進程之進程等待詳解

    這篇文章主要介紹了C語言控制進程之進程等待即回收子進程的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-08-08
  • C++ cin.get用法案例詳解

    C++ cin.get用法案例詳解

    這篇文章主要介紹了C++ cin.get用法案例詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下
    2021-08-08
  • 如何將C++源程序改寫為C語言

    如何將C++源程序改寫為C語言

    C++中主要的與C的區(qū)別最大而且最常用的特性及修改方法,接下來我們一起來學習他們吧
    2021-08-08
  • C++ 算法精講之貪心算法

    C++ 算法精講之貪心算法

    貪心算法(又稱貪婪算法)是指,在對問題求解時,總是做出在當前看來是最好的選擇。也就是說,不從整體最優(yōu)上加以考慮,他所做出的僅是在某種意義上的局部最優(yōu)解
    2022-03-03
  • Matlab實現帶豎線散點的核密度圖的繪制

    Matlab實現帶豎線散點的核密度圖的繪制

    核密度估計是用于估計隨機變量概率密度函數的一種非參數方法。核密度圖不失為一種用來觀察連續(xù)型變量分布的有效方法。本文將用Matlab實現帶豎線散點的核密度圖的繪制,感興趣的可以了解一下
    2022-08-08
  • C語言驅動開發(fā)之內核通過PEB獲取進程參數

    C語言驅動開發(fā)之內核通過PEB獲取進程參數

    PEB結構(Process Envirorment Block Structure)其中文名是進程環(huán)境塊信息。本文將通過PEB實現獲取進程參數,感興趣的小伙伴可以了解一下
    2022-10-10

最新評論