OpenCV实践之车流量统计(C++)
生活随笔
收集整理的這篇文章主要介紹了
OpenCV实践之车流量统计(C++)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
車流量統計
頭文件
#ifndef MY_BLOB #define MY_BLOB#include<opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> #include<opencv2/imgproc/imgproc.hpp>/// class Blob { public:// member variables ///std::vector<cv::Point> currentContour;cv::Rect currentBoundingRect;std::vector<cv::Point> centerPositions;double dblCurrentDiagonalSize;double dblCurrentAspectRatio;bool blnCurrentMatchFoundOrNewBlob;bool blnStillBeingTracked;int intNumOfConsecutiveFramesWithoutAMatch;cv::Point predictedNextPosition;// function prototypes Blob(std::vector<cv::Point> _contour);void predictNextPosition(void);};#endif // MY_BLOB // Blob.cpp#include "Blob.h"/// Blob::Blob(std::vector<cv::Point> _contour) {currentContour = _contour;currentBoundingRect = cv::boundingRect(currentContour);cv::Point currentCenter;currentCenter.x = (currentBoundingRect.x + currentBoundingRect.x + currentBoundingRect.width) / 2;currentCenter.y = (currentBoundingRect.y + currentBoundingRect.y + currentBoundingRect.height) / 2;centerPositions.push_back(currentCenter);dblCurrentDiagonalSize = sqrt(pow(currentBoundingRect.width, 2) + pow(currentBoundingRect.height, 2));dblCurrentAspectRatio = (float)currentBoundingRect.width / (float)currentBoundingRect.height;blnStillBeingTracked = true;blnCurrentMatchFoundOrNewBlob = true;intNumOfConsecutiveFramesWithoutAMatch = 0; }/// void Blob::predictNextPosition(void) {int numPositions = (int)centerPositions.size();if (numPositions == 1) {predictedNextPosition.x = centerPositions.back().x;predictedNextPosition.y = centerPositions.back().y;}else if (numPositions == 2) {int deltaX = centerPositions[1].x - centerPositions[0].x;int deltaY = centerPositions[1].y - centerPositions[0].y;predictedNextPosition.x = centerPositions.back().x + deltaX;predictedNextPosition.y = centerPositions.back().y + deltaY;}else if (numPositions == 3) {int sumOfXChanges = ((centerPositions[2].x - centerPositions[1].x) * 2) +((centerPositions[1].x - centerPositions[0].x) * 1);int deltaX = (int)std::round((float)sumOfXChanges / 3.0);int sumOfYChanges = ((centerPositions[2].y - centerPositions[1].y) * 2) +((centerPositions[1].y - centerPositions[0].y) * 1);int deltaY = (int)std::round((float)sumOfYChanges / 3.0);predictedNextPosition.x = centerPositions.back().x + deltaX;predictedNextPosition.y = centerPositions.back().y + deltaY;}else if (numPositions == 4) {int sumOfXChanges = ((centerPositions[3].x - centerPositions[2].x) * 3) +((centerPositions[2].x - centerPositions[1].x) * 2) +((centerPositions[1].x - centerPositions[0].x) * 1);int deltaX = (int)std::round((float)sumOfXChanges / 6.0);int sumOfYChanges = ((centerPositions[3].y - centerPositions[2].y) * 3) +((centerPositions[2].y - centerPositions[1].y) * 2) +((centerPositions[1].y - centerPositions[0].y) * 1);int deltaY = (int)std::round((float)sumOfYChanges / 6.0);predictedNextPosition.x = centerPositions.back().x + deltaX;predictedNextPosition.y = centerPositions.back().y + deltaY;}else if (numPositions >= 5) {int sumOfXChanges = ((centerPositions[numPositions - 1].x - centerPositions[numPositions - 2].x) * 4) +((centerPositions[numPositions - 2].x - centerPositions[numPositions - 3].x) * 3) +((centerPositions[numPositions - 3].x - centerPositions[numPositions - 4].x) * 2) +((centerPositions[numPositions - 4].x - centerPositions[numPositions - 5].x) * 1);int deltaX = (int)std::round((float)sumOfXChanges / 10.0);int sumOfYChanges = ((centerPositions[numPositions - 1].y - centerPositions[numPositions - 2].y) * 4) +((centerPositions[numPositions - 2].y - centerPositions[numPositions - 3].y) * 3) +((centerPositions[numPositions - 3].y - centerPositions[numPositions - 4].y) * 2) +((centerPositions[numPositions - 4].y - centerPositions[numPositions - 5].y) * 1);int deltaY = (int)std::round((float)sumOfYChanges / 10.0);predictedNextPosition.x = centerPositions.back().x + deltaX;predictedNextPosition.y = centerPositions.back().y + deltaY;}else {// should never get here}}主函數
// main.cpp#include<opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> #include<opencv2/imgproc/imgproc.hpp>#include<iostream> #include<conio.h> // it may be necessary to change or remove this line if not using Windows#include "Blob.h"#define SHOW_STEPS // un-comment or comment this line to show steps or not// global variables /// const cv::Scalar SCALAR_BLACK = cv::Scalar(0.0, 0.0, 0.0); const cv::Scalar SCALAR_WHITE = cv::Scalar(255.0, 255.0, 255.0); const cv::Scalar SCALAR_YELLOW = cv::Scalar(0.0, 255.0, 255.0); const cv::Scalar SCALAR_GREEN = cv::Scalar(0.0, 200.0, 0.0); const cv::Scalar SCALAR_RED = cv::Scalar(0.0, 0.0, 255.0);// function prototypes void matchCurrentFrameBlobsToExistingBlobs(std::vector<Blob> &existingBlobs, std::vector<Blob> ¤tFrameBlobs); void addBlobToExistingBlobs(Blob ¤tFrameBlob, std::vector<Blob> &existingBlobs, int &intIndex); void addNewBlob(Blob ¤tFrameBlob, std::vector<Blob> &existingBlobs); double distanceBetweenPoints(cv::Point point1, cv::Point point2); void drawAndShowContours(cv::Size imageSize, std::vector<std::vector<cv::Point> > contours, std::string strImageName); void drawAndShowContours(cv::Size imageSize, std::vector<Blob> blobs, std::string strImageName); bool checkIfBlobsCrossedTheLine(std::vector<Blob> &blobs, int &intHorizontalLinePosition, int &carCount); void drawBlobInfoOnImage(std::vector<Blob> &blobs, cv::Mat &imgFrame2Copy); void drawCarCountOnImage(int &carCount, cv::Mat &imgFrame2Copy);/// int main(void) {cv::VideoCapture capVideo;cv::Mat imgFrame1;cv::Mat imgFrame2;std::vector<Blob> blobs;cv::Point crossingLine[2];int carCount = 0;capVideo.open("CarsDrivingUnderBridge.mp4");if (!capVideo.isOpened()){ // if unable to open video filestd::cout << "error reading video file" << std::endl << std::endl; // show error message_getch(); // it may be necessary to change or remove this line if not using Windowsreturn(0); // and exit program}if (capVideo.get(CV_CAP_PROP_FRAME_COUNT) < 2){std::cout << "error: video file must have at least two frames";_getch(); // it may be necessary to change or remove this line if not using Windowsreturn(0);}capVideo.read(imgFrame1);capVideo.read(imgFrame2);int intHorizontalLinePosition = (int)std::round((double)imgFrame1.rows * 0.35);crossingLine[0].x = 0;crossingLine[0].y = intHorizontalLinePosition;crossingLine[1].x = imgFrame1.cols - 1;crossingLine[1].y = intHorizontalLinePosition;char chCheckForEscKey = 0;bool blnFirstFrame = true;int frameCount = 2;while (capVideo.isOpened() && chCheckForEscKey != 27) {std::vector<Blob> currentFrameBlobs;cv::Mat imgFrame1Copy = imgFrame1.clone();cv::Mat imgFrame2Copy = imgFrame2.clone();cv::Mat imgDifference;cv::Mat imgThresh;cv::cvtColor(imgFrame1Copy, imgFrame1Copy, CV_BGR2GRAY);cv::cvtColor(imgFrame2Copy, imgFrame2Copy, CV_BGR2GRAY);cv::GaussianBlur(imgFrame1Copy, imgFrame1Copy, cv::Size(5, 5), 0);cv::GaussianBlur(imgFrame2Copy, imgFrame2Copy, cv::Size(5, 5), 0);cv::absdiff(imgFrame1Copy, imgFrame2Copy, imgDifference);cv::threshold(imgDifference, imgThresh, 30, 255.0, CV_THRESH_BINARY);cv::imshow("imgThresh", imgThresh);cv::Mat structuringElement3x3 = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));cv::Mat structuringElement5x5 = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));cv::Mat structuringElement7x7 = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(7, 7));cv::Mat structuringElement15x15 = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(15, 15));for (unsigned int i = 0; i < 2; i++){cv::dilate(imgThresh, imgThresh, structuringElement5x5);cv::dilate(imgThresh, imgThresh, structuringElement5x5);cv::erode(imgThresh, imgThresh, structuringElement5x5);}cv::Mat imgThreshCopy = imgThresh.clone();std::vector<std::vector<cv::Point> > contours;cv::findContours(imgThreshCopy, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);drawAndShowContours(imgThresh.size(), contours, "imgContours");std::vector<std::vector<cv::Point> > convexHulls(contours.size());for (unsigned int i = 0; i < contours.size(); i++) {cv::convexHull(contours[i], convexHulls[i]);}drawAndShowContours(imgThresh.size(), convexHulls, "imgConvexHulls");for (auto &convexHull : convexHulls){Blob possibleBlob(convexHull);if (possibleBlob.currentBoundingRect.area() > 400 &&possibleBlob.dblCurrentAspectRatio > 0.2 &&possibleBlob.dblCurrentAspectRatio < 4.0 &&possibleBlob.currentBoundingRect.width > 30 &&possibleBlob.currentBoundingRect.height > 30 &&possibleBlob.dblCurrentDiagonalSize > 60.0 &&(cv::contourArea(possibleBlob.currentContour) / (double)possibleBlob.currentBoundingRect.area()) > 0.50) {currentFrameBlobs.push_back(possibleBlob);}}drawAndShowContours(imgThresh.size(), currentFrameBlobs, "imgCurrentFrameBlobs");if (blnFirstFrame == true) {for (auto ¤tFrameBlob : currentFrameBlobs) {blobs.push_back(currentFrameBlob);}}else{matchCurrentFrameBlobsToExistingBlobs(blobs, currentFrameBlobs);}drawAndShowContours(imgThresh.size(), blobs, "imgBlobs");imgFrame2Copy = imgFrame2.clone(); // get another copy of frame 2 since we changed the previous frame 2 copy in the processing abovedrawBlobInfoOnImage(blobs, imgFrame2Copy);bool blnAtLeastOneBlobCrossedTheLine = checkIfBlobsCrossedTheLine(blobs, intHorizontalLinePosition, carCount);if (blnAtLeastOneBlobCrossedTheLine == true){cv::line(imgFrame2Copy, crossingLine[0], crossingLine[1], SCALAR_GREEN, 2);}else {cv::line(imgFrame2Copy, crossingLine[0], crossingLine[1], SCALAR_RED, 2);}drawCarCountOnImage(carCount, imgFrame2Copy);cv::imshow("imgFrame2Copy", imgFrame2Copy);//cv::waitKey(0); // uncomment this line to go frame by frame for debugging// now we prepare for the next iterationcurrentFrameBlobs.clear();imgFrame1 = imgFrame2.clone(); // move frame 1 up to where frame 2 isif ((capVideo.get(CV_CAP_PROP_POS_FRAMES) + 1) < capVideo.get(CV_CAP_PROP_FRAME_COUNT)) {capVideo.read(imgFrame2);}else {std::cout << "end of video\n";break;}blnFirstFrame = false;frameCount++;chCheckForEscKey = cv::waitKey(1);}if (chCheckForEscKey != 27) { // if the user did not press esc (i.e. we reached the end of the video)cv::waitKey(0); // hold the windows open to allow the "end of video" message to show}// note that if the user did press esc, we don't need to hold the windows open, we can simply let the program end which will close the windowsreturn(0); }/// void matchCurrentFrameBlobsToExistingBlobs(std::vector<Blob> &existingBlobs, std::vector<Blob> ¤tFrameBlobs) {for (auto &existingBlob : existingBlobs) {existingBlob.blnCurrentMatchFoundOrNewBlob = false;existingBlob.predictNextPosition();}for (auto ¤tFrameBlob : currentFrameBlobs) {int intIndexOfLeastDistance = 0;double dblLeastDistance = 100000.0;for (unsigned int i = 0; i < existingBlobs.size(); i++) {if (existingBlobs[i].blnStillBeingTracked == true) {double dblDistance = distanceBetweenPoints(currentFrameBlob.centerPositions.back(), existingBlobs[i].predictedNextPosition);if (dblDistance < dblLeastDistance) {dblLeastDistance = dblDistance;intIndexOfLeastDistance = i;}}}if (dblLeastDistance < currentFrameBlob.dblCurrentDiagonalSize * 0.5) {addBlobToExistingBlobs(currentFrameBlob, existingBlobs, intIndexOfLeastDistance);}else {addNewBlob(currentFrameBlob, existingBlobs);}}for (auto &existingBlob : existingBlobs) {if (existingBlob.blnCurrentMatchFoundOrNewBlob == false) {existingBlob.intNumOfConsecutiveFramesWithoutAMatch++;}if (existingBlob.intNumOfConsecutiveFramesWithoutAMatch >= 5) {existingBlob.blnStillBeingTracked = false;}}}/// void addBlobToExistingBlobs(Blob ¤tFrameBlob, std::vector<Blob> &existingBlobs, int &intIndex) {existingBlobs[intIndex].currentContour = currentFrameBlob.currentContour;existingBlobs[intIndex].currentBoundingRect = currentFrameBlob.currentBoundingRect;existingBlobs[intIndex].centerPositions.push_back(currentFrameBlob.centerPositions.back());existingBlobs[intIndex].dblCurrentDiagonalSize = currentFrameBlob.dblCurrentDiagonalSize;existingBlobs[intIndex].dblCurrentAspectRatio = currentFrameBlob.dblCurrentAspectRatio;existingBlobs[intIndex].blnStillBeingTracked = true;existingBlobs[intIndex].blnCurrentMatchFoundOrNewBlob = true; }/// void addNewBlob(Blob ¤tFrameBlob, std::vector<Blob> &existingBlobs) {currentFrameBlob.blnCurrentMatchFoundOrNewBlob = true;existingBlobs.push_back(currentFrameBlob); }/// double distanceBetweenPoints(cv::Point point1, cv::Point point2) {int intX = abs(point1.x - point2.x);int intY = abs(point1.y - point2.y);return(sqrt(pow(intX, 2) + pow(intY, 2))); }/// void drawAndShowContours(cv::Size imageSize, std::vector<std::vector<cv::Point> > contours, std::string strImageName) {cv::Mat image(imageSize, CV_8UC3, SCALAR_BLACK);cv::drawContours(image, contours, -1, SCALAR_WHITE, -1);cv::imshow(strImageName, image); }/// void drawAndShowContours(cv::Size imageSize, std::vector<Blob> blobs, std::string strImageName) {cv::Mat image(imageSize, CV_8UC3, SCALAR_BLACK);std::vector<std::vector<cv::Point> > contours;for (auto &blob : blobs) {if (blob.blnStillBeingTracked == true) {contours.push_back(blob.currentContour);}}cv::drawContours(image, contours, -1, SCALAR_WHITE, -1);cv::imshow(strImageName, image); }/// bool checkIfBlobsCrossedTheLine(std::vector<Blob> &blobs, int &intHorizontalLinePosition, int &carCount) {bool blnAtLeastOneBlobCrossedTheLine = false;for (auto blob : blobs) {if (blob.blnStillBeingTracked == true && blob.centerPositions.size() >= 2) {int prevFrameIndex = (int)blob.centerPositions.size() - 2;int currFrameIndex = (int)blob.centerPositions.size() - 1;if (blob.centerPositions[prevFrameIndex].y > intHorizontalLinePosition && blob.centerPositions[currFrameIndex].y <= intHorizontalLinePosition) {carCount++;blnAtLeastOneBlobCrossedTheLine = true;}}}return blnAtLeastOneBlobCrossedTheLine; }/// void drawBlobInfoOnImage(std::vector<Blob> &blobs, cv::Mat &imgFrame2Copy) {for (unsigned int i = 0; i < blobs.size(); i++) {if (blobs[i].blnStillBeingTracked == true) {cv::rectangle(imgFrame2Copy, blobs[i].currentBoundingRect, SCALAR_RED, 2);int intFontFace = CV_FONT_HERSHEY_SIMPLEX;double dblFontScale = blobs[i].dblCurrentDiagonalSize / 60.0;int intFontThickness = (int)std::round(dblFontScale * 1.0);cv::putText(imgFrame2Copy, std::to_string(i), blobs[i].centerPositions.back(), intFontFace, dblFontScale, SCALAR_GREEN, intFontThickness);}} }/// void drawCarCountOnImage(int &carCount, cv::Mat &imgFrame2Copy) {int intFontFace = CV_FONT_HERSHEY_SIMPLEX;double dblFontScale = (imgFrame2Copy.rows * imgFrame2Copy.cols) / 300000.0;int intFontThickness = (int)std::round(dblFontScale * 1.5);cv::Size textSize = cv::getTextSize(std::to_string(carCount), intFontFace, dblFontScale, intFontThickness, 0);cv::Point ptTextBottomLeftPosition;ptTextBottomLeftPosition.x = imgFrame2Copy.cols - 1 - (int)((double)textSize.width * 1.25);ptTextBottomLeftPosition.y = (int)((double)textSize.height * 1.25);cv::putText(imgFrame2Copy, std::to_string(carCount), ptTextBottomLeftPosition, intFontFace, dblFontScale, SCALAR_GREEN, intFontThickness);}轉自(https://github.com/MicrocontrollersAndMore/OpenCV_3_Car_Counting_Cpp)
總結
以上是生活随笔為你收集整理的OpenCV实践之车流量统计(C++)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 前端学习(1802):前端调试之事件伪类
- 下一篇: 蓝桥杯官网 试题 PREV-94 历届真