云南做網(wǎng)站價(jià)格雅思培訓(xùn)班價(jià)格一般多少
關(guān)于C++版本幀差法可以參考博客
[C++]OpenCV基于幀差法的運(yùn)動(dòng)檢測(cè)-CSDN博客https://blog.csdn.net/FL1768317420/article/details/137397811?spm=1001.2014.3001.5501
我們將參考C++版本轉(zhuǎn)成opencvsharp版本。
幀差法,也叫做幀間差分法,這里引用百度百科上的一段定義:
幀間差分法是一種通過(guò)對(duì)視頻圖像序列中相鄰兩幀作差分運(yùn)算來(lái)獲得運(yùn)動(dòng)目標(biāo)輪廓的方法,它可以很好地適用于存在多個(gè)運(yùn)動(dòng)目標(biāo)和攝像機(jī)移動(dòng)的情況。當(dāng)監(jiān)控場(chǎng)景中出現(xiàn)異常物體運(yùn)動(dòng)時(shí),幀與幀之間會(huì)出現(xiàn)較為明顯的差別,兩幀相減,得到兩幀圖像亮度差的絕對(duì)值,判斷它是否大于閾值來(lái)分析視頻或圖像序列的運(yùn)動(dòng)特性,確定圖像序列中有無(wú)物體運(yùn)動(dòng)。圖像序列逐幀的差分,相當(dāng)于對(duì)圖像序列進(jìn)行了時(shí)域下的高通濾波。
最簡(jiǎn)單的幀差法就是二幀差分法,將視頻流中的前后兩幀圖像轉(zhuǎn)換為灰度圖像,再經(jīng)過(guò)高斯模糊消除噪聲干擾,然后將兩幀圖像進(jìn)行相減操作得到兩幀圖像之間的差異區(qū)域,再對(duì)差異圖像進(jìn)行二值分割把差異區(qū)域作為前景、不變區(qū)域作為背景,并且進(jìn)行開(kāi)運(yùn)算操作來(lái)消除一些微小干擾。這樣,就得到了兩幀圖像中明顯不同的區(qū)域,也就是運(yùn)動(dòng)的目標(biāo)物體。下面對(duì)上述博客C++版本做解讀:
這段C++ OpenCV代碼實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的運(yùn)動(dòng)檢測(cè)算法,采用兩幀差法來(lái)識(shí)別視頻中的運(yùn)動(dòng)區(qū)域。以下是代碼逐段解讀:1. 初始化視頻捕獲器VideoCapture capture;
capture.open("D:\\opencv_c++\\opencv_tutorial\\data\\images\\bike.avi");
這段代碼創(chuàng)建了一個(gè)VideoCapture對(duì)象capture,用于打開(kāi)和讀取視頻文件。這里嘗試打開(kāi)位于指定路徑的bike.avi視頻文件。2. 檢查視頻是否成功打開(kāi)if (!capture.isOpened())
{return 0;
}
使用capture.isOpened()檢查視頻文件是否成功打開(kāi)。如果未能成功打開(kāi)(返回false),則立即結(jié)束程序并返回值0。3. 定義所需圖像變量Mat pre_frame, current_frame, pre_gray, current_gray, pre_gaus, current_gaus;
定義一系列Mat對(duì)象(OpenCV中的多通道圖像容器),用于存儲(chǔ)不同處理階段的圖像數(shù)據(jù):pre_frame 和 current_frame 分別存儲(chǔ)前一幀和當(dāng)前幀的彩色圖像。
pre_gray 和 current_gray 存儲(chǔ)對(duì)應(yīng)的灰度圖像。
pre_gaus 和 current_gaus 存儲(chǔ)經(jīng)過(guò)高斯模糊處理的灰度圖像。
4. 讀取第一幀并進(jìn)行預(yù)處理capture.read(pre_frame);
cvtColor(pre_frame, pre_gray, COLOR_BGR2GRAY);
GaussianBlur(pre_gray, pre_gaus, Size(), 5, 5);
首先從視頻中讀取第一幀到pre_frame。接著,使用cvtColor函數(shù)將其轉(zhuǎn)換為灰度圖像并存儲(chǔ)在pre_gray中。最后,對(duì)pre_gray應(yīng)用高斯模糊(核大小為5x5),結(jié)果存放在pre_gaus。5. 循環(huán)處理后續(xù)幀while (capture.read(current_frame))
{// ... 處理代碼 ...
}
進(jìn)入主循環(huán),每次迭代從視頻中讀取下一幀至current_frame。當(dāng)無(wú)法再讀取到新幀時(shí)(即視頻播放完畢),循環(huán)結(jié)束。6. 當(dāng)前幀預(yù)處理cvtColor(current_frame, current_gray, COLOR_BGR2GRAY);
GaussianBlur(current_gray, current_gaus, Size(), 5, 5);
對(duì)當(dāng)前幀執(zhí)行與第一幀相同的預(yù)處理步驟:轉(zhuǎn)換為灰度圖像(current_gray)并應(yīng)用高斯模糊(current_gaus)。7. 計(jì)算兩幀差分Mat sub_gray, sub_binary, sub_open;
subtract(current_gaus, pre_gaus, sub_gray);
threshold(sub_gray, sub_binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
計(jì)算current_gaus與pre_gaus之間的像素差值,結(jié)果存儲(chǔ)在sub_gray。然后,對(duì)sub_gray應(yīng)用二值化閾值處理(包括Otsu自適應(yīng)閾值),得到運(yùn)動(dòng)區(qū)域的二值圖像sub_binary。8. 形態(tài)學(xué)開(kāi)運(yùn)算Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));
morphologyEx(sub_binary, sub_open, MORPH_OPEN, kernel, Point(-1, -1), 1, 0);
創(chuàng)建一個(gè)大小為5x5的矩形結(jié)構(gòu)元素kernel。接著,對(duì)sub_binary進(jìn)行形態(tài)學(xué)開(kāi)運(yùn)算(去除小噪聲),輸出結(jié)果保存在sub_open。9. 顯示結(jié)果imshow("sub_open", sub_open);
imshow("current_frame", current_frame);
使用imshow函數(shù)分別顯示運(yùn)動(dòng)區(qū)域檢測(cè)結(jié)果sub_open和當(dāng)前幀原始彩色圖像current_frame。10. 更新前一幀信息cpp
swap(pre_gaus, current_gaus);
使用swap函數(shù)交換pre_gaus和current_gaus的內(nèi)容,使得pre_gaus存儲(chǔ)當(dāng)前幀高斯模糊后的灰度圖像,為下一次循環(huán)做好準(zhǔn)備。11. 檢查用戶輸入以決定是否退出char ch = cv::waitKey(20);
if (ch == 27)
{break;
}
waitKey(20)函數(shù)等待用戶按鍵,同時(shí)設(shè)置超時(shí)時(shí)間為20毫秒。若在該時(shí)間內(nèi)接收到按鍵事件,返回按鍵的ASCII碼;否則返回-1。這里檢查是否按下Esc鍵(ASCII碼為27),如果是,則跳出循環(huán),結(jié)束視頻處理。綜上所述,這段代碼實(shí)現(xiàn)了基于兩幀差法的運(yùn)動(dòng)檢測(cè)算法,通過(guò)對(duì)連續(xù)視頻幀進(jìn)行灰度化、高斯模糊、差分、二值化、形態(tài)學(xué)開(kāi)運(yùn)算等步驟,提取出運(yùn)動(dòng)區(qū)域并在窗口中實(shí)時(shí)顯示,同時(shí)允許用戶按Esc鍵隨時(shí)停止處理。
三幀差分法是將連續(xù)的三幀圖像,分別進(jìn)行轉(zhuǎn)灰度圖、高斯模糊消除噪聲干擾,然后進(jìn)行逐幀相減,也就是后一幀圖像減去當(dāng)前幀圖像、當(dāng)前幀圖像減去前一幀圖像,從而得到兩張差異圖像。再將得到的兩個(gè)差值圖像進(jìn)行與操作,得到共同的差異區(qū)域,最后通過(guò)開(kāi)運(yùn)算操作消除微小干擾。這樣就得到了三幀圖像間的明顯差異區(qū)域,也就是運(yùn)動(dòng)的目標(biāo)物體。
而且二幀差分法對(duì)于微小運(yùn)動(dòng)物體的檢測(cè)能力比較差,因?yàn)槿绻趦蓭瑘D像之間變化太小,就很難被檢測(cè)出來(lái)。而三幀差分法利用連續(xù)三幀圖像的差異結(jié)果,能夠提高對(duì)微小運(yùn)動(dòng)物體的檢測(cè)能力,同時(shí)增強(qiáng)對(duì)噪聲、光照等因素的抗干擾能力。以下是對(duì)C++代碼解讀:
這段C++ OpenCV代碼同樣實(shí)現(xiàn)了一個(gè)基于兩幀差法的運(yùn)動(dòng)檢測(cè)算法,但與之前提供的代碼相比,它采用了雙緩沖機(jī)制,即同時(shí)保留兩前一幀的信息,以增強(qiáng)對(duì)運(yùn)動(dòng)檢測(cè)的穩(wěn)定性。以下是詳細(xì)解讀:1. 初始化視頻捕獲器cpp
VideoCapture capture;
capture.open("D:\\opencv_c++\\opencv_tutorial\\data\\images\\bike.avi");
創(chuàng)建一個(gè)VideoCapture對(duì)象capture,用于打開(kāi)并讀取視頻文件。這里嘗試打開(kāi)位于指定路徑的bike.avi視頻文件。2. 檢查視頻是否成功打開(kāi)cpp
if (!capture.isOpened())
{return 0;
}
使用capture.isOpened()檢查視頻文件是否成功打開(kāi)。如果未能成功打開(kāi)(返回false),則立即結(jié)束程序并返回值0。3. 定義所需圖像變量cpp
Mat pre_frame1, pre_frame2, current_frame,pre_gray1, pre_gray2, current_gray,pre_gaus1, pre_gaus2, current_gaus;
定義一系列Mat對(duì)象,用于存儲(chǔ)不同處理階段的圖像數(shù)據(jù):pre_frame1 和 pre_frame2 分別存儲(chǔ)最近兩幀的彩色圖像。
current_frame 存儲(chǔ)當(dāng)前幀的彩色圖像。
pre_gray1 和 pre_gray2 存儲(chǔ)對(duì)應(yīng)的灰度圖像。
current_gray 存儲(chǔ)當(dāng)前幀的灰度圖像。
pre_gaus1 和 pre_gaus2 存儲(chǔ)最近兩幀經(jīng)過(guò)高斯模糊處理的灰度圖像。
current_gaus 存儲(chǔ)當(dāng)前幀經(jīng)過(guò)高斯模糊處理的灰度圖像。
4. 讀取前兩幀并進(jìn)行預(yù)處理cpp
capture.read(pre_frame1);
capture.read(pre_frame2);cvtColor(pre_frame1, pre_gray1, COLOR_BGR2GRAY);
cvtColor(pre_frame2, pre_gray2, COLOR_BGR2GRAY);GaussianBlur(pre_gray1, pre_gaus1, Size(), 10, 0);
GaussianBlur(pre_gray2, pre_gaus2, Size(), 10, 0);
從視頻中讀取前兩幀分別存入pre_frame1和pre_frame2。對(duì)這兩幀進(jìn)行灰度化處理后分別存儲(chǔ)在pre_gray1和pre_gray2,接著對(duì)灰度圖像應(yīng)用高斯模糊(核大小為10x10),結(jié)果分別存放在pre_gaus1和pre_gaus2。5. 主循環(huán)處理后續(xù)幀cpp
while (capture.read(current_frame))
{// ... 處理代碼 ...
}
進(jìn)入主循環(huán),每次迭代從視頻中讀取下一幀至current_frame。當(dāng)無(wú)法再讀取到新幀時(shí)(即視頻播放完畢),循環(huán)結(jié)束。6. 當(dāng)前幀預(yù)處理cpp
cvtColor(current_frame, current_gray, COLOR_BGR2GRAY);
GaussianBlur(current_gray, current_gaus, Size(), 10, 0);
對(duì)當(dāng)前幀執(zhí)行與前兩幀相同的預(yù)處理步驟:轉(zhuǎn)換為灰度圖像(current_gray)并應(yīng)用高斯模糊(current_gaus)。7. 計(jì)算兩幀差分cpp
Mat diff1, diff2, diff;subtract(pre_gaus2, pre_gaus1, diff1);
subtract(current_gaus, pre_gaus2, diff2);
計(jì)算pre_gaus2與pre_gaus1以及current_gaus與pre_gaus2之間的像素差值,結(jié)果分別存儲(chǔ)在diff1和diff2。8. 差分圖像二值化cpp
Mat diff1_binary, diff2_binary;threshold(diff1, diff1_binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
threshold(diff2, diff2_binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
對(duì)diff1和diff2分別應(yīng)用二值化閾值處理(包括Otsu自適應(yīng)閾值),得到運(yùn)動(dòng)區(qū)域的二值圖像diff1_binary和diff2_binary。9. 邏輯與操作合并差分結(jié)果cpp
bitwise_and(diff1_binary, diff2_binary, diff);
對(duì)diff1_binary和diff2_binary進(jìn)行邏輯與(AND)操作,僅保留兩者都為運(yùn)動(dòng)區(qū)域的像素,生成更穩(wěn)定的運(yùn)動(dòng)檢測(cè)結(jié)果,存儲(chǔ)在diff中。10. 形態(tài)學(xué)開(kāi)運(yùn)算cpp
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
morphologyEx(diff, diff, MORPH_OPEN, kernel, Point(-1, -1), 1, 0);
創(chuàng)建一個(gè)大小為3x3的矩形結(jié)構(gòu)元素kernel。接著,對(duì)diff進(jìn)行形態(tài)學(xué)開(kāi)運(yùn)算(去除小噪聲),輸出結(jié)果仍保存在diff。11. 顯示結(jié)果cpp
imshow("diff", diff);
imshow("current_frame", current_frame);
使用imshow函數(shù)分別顯示運(yùn)動(dòng)區(qū)域檢測(cè)結(jié)果diff和當(dāng)前幀原始彩色圖像current_frame。12. 更新前兩幀信息cpp
pre_gaus1 = pre_gaus2.clone();
pre_gaus2 = current_gaus.clone();
使用clone函數(shù)復(fù)制pre_gaus2和current_gaus的內(nèi)容,使得pre_gaus1和pre_gaus2分別存儲(chǔ)前兩幀高斯模糊后的灰度圖像,為下一次循環(huán)做好準(zhǔn)備。13. 檢查用戶輸入以決定是否退出cpp
char ch = cv::waitKey(20);
if (ch == 27)
{break;
}
waitKey(20)函數(shù)等待用戶按鍵,同時(shí)設(shè)置超時(shí)時(shí)間為20毫秒。若在該時(shí)間內(nèi)接收到按鍵事件,返回按鍵的ASCII碼;否則返回-1。這里檢查是否按下Esc鍵(ASCII碼為27),如果是,則跳出循環(huán),結(jié)束視頻處理??偨Y(jié):這段代碼通過(guò)雙緩沖機(jī)制(同時(shí)保留兩前一幀信息)實(shí)現(xiàn)了一種改進(jìn)的基于兩幀差法的運(yùn)動(dòng)檢測(cè)算法。算法流程包括讀取幀、預(yù)處理、差分計(jì)算、二值化、邏輯與操作、形態(tài)學(xué)開(kāi)運(yùn)算等步驟,最終提取出穩(wěn)定運(yùn)動(dòng)區(qū)域并在窗口中實(shí)時(shí)顯示,同時(shí)允許用戶按Esc鍵隨時(shí)停止處理。
知道上面步驟我們可以很輕松翻譯成opencvsharp代碼
【效果展示】
【測(cè)試環(huán)境】
vs2019,netframework4.7.2,opencvsharp4.8.0
【opencvsharp演示代碼下載地址】?
https://download.csdn.net/download/FL1623863129/89085049