【opencv學習之四十二】簡單運動檢測
阿新 • • 發佈:2019-01-06
視訊運動檢測基本思想是進行每一幀對比,檢測不同然後得出是否運動,一般分為兩種,背景法和差幀法;
背景法是:將一幅圖作為背景,讓後和每一幀對比;缺點是一開始存入的背景可能隨光照變法而造成錯誤,但是可以用在光照環境穩定的地方,優點是可以檢測之前背景沒有的景象;
差幀法是:將前一幀和後一幀進行對比;缺點是無法對運動後突然又靜止的景象進行識別,優點是光照不影響;
例項背景法:
///////////////////////運動檢測,攝像頭檢測,背景法 Mat MoveDetectBack(Mat background,Mat frame);//宣告運動檢測函式 void imgMoveDetectionBack() { /*VideoCapture結構體,儲存影象資訊,open()引數為int index(0為預設攝像頭),讀入攝像頭視訊, open()引數為路徑,讀入視訊檔案*/ VideoCapture cap(0); // 開啟攝像頭0 if (!cap.isOpened()) // 異常處理 { QMessageBox mesg; mesg.about(NULL,"提示","攝像頭開啟失敗"); waitKey(1000); } Mat frame;//儲存幀 Mat background;//儲存背景影象 Mat result;//儲存結果影象 //先儲存背景 bool firstF= cap.read(frame); // 先獲取一幀 //異常處理 if (!firstF) { QMessageBox mesg; mesg.about(NULL,"提示","Cannot read a frame from video stream"); } else {background = frame.clone();}//儲存背景 //迴圈檢測視訊 while (1) { bool bSuccess = cap.read(frame); // 讀取 if (!bSuccess) //異常處理 { QMessageBox mesg; mesg.about(NULL,"提示","Cannot read a frame from video stream"); break; } /////////////////////////////////////////////////////////////////////////// if (frame.empty())//對幀進行異常檢測 { cout << "frame is empty!" << endl; break; } //將背景和每一幀做差 result = MoveDetectBack(background, frame);//呼叫MoveDetect()進行運動物體檢測,返回值存入result imshow("result", result); ////////////////////////////////////////////////////////// if (waitKey(30) == 27) //按鍵退出 { QMessageBox mesg; mesg.about(NULL,"資訊","退出攝像"); break; } } waitKey(10); cap.release(); } //檢測函式 Mat MoveDetectBack(Mat background, Mat frame) { Mat result = frame.clone(); //1.將background和frame轉為灰度圖 Mat gray1, gray2; cvtColor(background, gray1, CV_BGR2GRAY); cvtColor(frame, gray2, CV_BGR2GRAY); //2.將background和frame做差 Mat m_different; absdiff(gray1, gray2, m_different); imshow("m_different", m_different); //3.對差值圖diff_thresh進行閾值化處理 Mat Dif_Thresh; threshold(m_different, Dif_Thresh, 50, 255, CV_THRESH_BINARY); imshow("Dif_Thresh",Dif_Thresh); //4.腐蝕 Mat kernel_erode = getStructuringElement(MORPH_RECT, Size(3, 3)); Mat kernel_dilate = getStructuringElement(MORPH_RECT, Size(15, 15)); erode(Dif_Thresh, Dif_Thresh, kernel_erode); imshow("erode", Dif_Thresh); //5.膨脹 dilate(Dif_Thresh, Dif_Thresh, kernel_dilate); imshow("dilate", Dif_Thresh); //6.查詢輪廓並繪製輪廓 vector<vector<Point>> contours; findContours(Dif_Thresh, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); drawContours(result, contours, -1, Scalar(0, 0, 255), 2);//在result上繪製輪廓 //7.查詢正外接矩形 vector<Rect> boundRect(contours.size()); for (int i = 0; i < contours.size(); i++) { boundRect[i] = boundingRect(contours[i]); rectangle(result, boundRect[i], Scalar(0, 255, 0), 2);//在result上繪製正外接矩形 } return result;//返回result }
效果:
差幀法:
///////////////////////運動檢測3,攝像頭檢測,差幀法 Mat MoveDetect3(Mat background,Mat frame);//宣告運動檢測函式 void imgMoveDetection3() { /*VideoCapture結構體,儲存影象資訊,open()引數為int index(0為預設攝像頭),讀入攝像頭視訊, open()引數為路徑,讀入視訊檔案*/ VideoCapture cap(0); // 開啟攝像頭0 if (!cap.isOpened()) // 異常處理 { QMessageBox mesg; mesg.about(NULL,"提示","攝像頭開啟失敗"); waitKey(1000); } Mat frame;//儲存幀 Mat temp;//儲存前一幀影象 Mat result;//儲存結果影象 while (1) { bool bSuccess = cap.read(frame); // 獲取一幀 if (!bSuccess) //異常處理 { QMessageBox mesg; mesg.about(NULL,"提示","Cannot read a frame from video stream"); break; } /////////////////////////////////////////////////////////////////////////// if (frame.empty())//對幀進行異常檢測 { cout << "frame is empty!" << endl; break; } if ( temp.empty())//如果temp為空則為第一幀 { result = MoveDetect3(frame, frame);//呼叫MoveDetect()進行運動物體檢測,返回值存入result } else//若不是第一幀(temp有值了) { result = MoveDetect3(temp, frame);//呼叫MoveDetect()進行運動物體檢測,返回值存入result } imshow("result", result); temp = frame.clone(); ////////////////////////////////////////////////////////// if (waitKey(30) == 27) //按鍵退出 { QMessageBox mesg; mesg.about(NULL,"資訊","退出攝像"); break; } } waitKey(10); cap.release(); } //檢測函式 Mat MoveDetect3(Mat background, Mat frame) { Mat result = frame.clone(); //1.將background和frame轉為灰度圖 Mat gray1, gray2; cvtColor(background, gray1, CV_BGR2GRAY); cvtColor(frame, gray2, CV_BGR2GRAY); //2.將background和frame做差 Mat m_different; absdiff(gray1, gray2, m_different); imshow("m_different", m_different); //3.對差值圖diff_thresh進行閾值化處理 Mat Dif_Thresh; threshold(m_different, Dif_Thresh, 50, 255, CV_THRESH_BINARY); imshow("Dif_Thresh",Dif_Thresh); //4.腐蝕 Mat kernel_erode = getStructuringElement(MORPH_RECT, Size(3, 3)); Mat kernel_dilate = getStructuringElement(MORPH_RECT, Size(15, 15)); erode(Dif_Thresh, Dif_Thresh, kernel_erode); imshow("erode", Dif_Thresh); //5.膨脹 dilate(Dif_Thresh, Dif_Thresh, kernel_dilate); imshow("dilate", Dif_Thresh); //6.查詢輪廓並繪製輪廓 vector<vector<Point>> contours; findContours(Dif_Thresh, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); drawContours(result, contours, -1, Scalar(0, 0, 255), 2);//在result上繪製輪廓 //7.查詢正外接矩形 vector<Rect> boundRect(contours.size()); for (int i = 0; i < contours.size(); i++) { boundRect[i] = boundingRect(contours[i]); rectangle(result, boundRect[i], Scalar(0, 255, 0), 2);//在result上繪製正外接矩形 } return result;//返回result }
效果: