本篇主要解决物体越线问题,当运行代码时,视频会停在第一帧,这时可以用鼠标划出一条线段,作为越界的标准线。
当画完之后视频自动运行,有行人或者物体运动时会被检测出来并标出外接矩形框,当外接矩形框与画出线段相交时,会显示物体越界或物体越线,本产品用于公共场所的行为规范安全问题。
#include #include #include #include #include #include #include #include #include #include #include using namespace cv; using namespace std; /*--------------------------------定义鼠标事件--画直线--------------------------*/ bool got_line = false; //全局变量 Point beginPoint = Point(0, 0);//--注意这个有一个初始化的(0,0) bool got_beigin_point = false; Point endPoint = Point(0, 0);//--注意这个有一个自己默认的初始化(0,0) void mouseLineHandler(int event, int x, int y, int flags, void *param) { switch (event) { case CV_EVENT_LBUTTONDOWN: beginPoint = Point(x, y); endPoint = beginPoint; got_beigin_point = true; break; case CV_EVENT_MOUSEMOVE: if (got_beigin_point) { endPoint = Point(x, y); } break; case CV_EVENT_LBUTTONUP: got_line = true; endPoint = Point(x, y); break; default: break; } } //判断两条线段相交 bool intersection(const vector & line1, const vector &line2)//vector line(2),代表一线段 { CV_Assert(line1.size() == line2.size()); CV_Assert(line1.size() == 2); Point point1_11, point1_12, point1_21, point1_22; //首先判断line1的两个端点,在line2的两侧 point1_11 = line2[0] - line1[0]; point1_12 = line2[1] - line1[0]; point1_21 = line2[0] - line1[1]; point1_22 = line2[1] - line1[1]; //point1_11.cross(point1_12)*point1_21.cross(point1_22)<0;//----------表明在两侧 //再次判断line2的两个端点,在line1的两侧 Point point2_11, point2_12, point2_21, point2_22; point2_11 = line1[0] - line2[0]; point2_12 = line1[1] - line2[0]; point2_21 = line1[0] - line2[1]; point2_22 = line1[1] - line2[1]; //point2_11.cross(point2_12)*point2_21.cross(point2_22)<0; //return (point1_11.cross(point1_12)*point1_21.cross(point1_22)<0 && point2_11.cross(point2_12)*point2_21.cross(point2_22)<0); if (point1_11.cross(point1_12)*point1_21.cross(point1_22) < 0 && point2_11.cross(point2_12)*point2_21.cross(point2_22) < 0) { return true; } else { return false; } } bool rect_line_intersection(const vector & line, const Rect & targetRect)//rect的四个顶点(roi.x,roi.y),(roi.x,roi.y+roi.height-1),(roi.x+roi.width-1,roi.y),(roi.x+roi.width-1,roi.y+roi.height-1) { vector line1; line1.clear(); line1.push_back(Point(targetRect.x, targetRect.y)); line1.push_back(Point(targetRect.x, targetRect.y + targetRect.height - 1)); //if (intersection(line1, line)) // return true; vector line2; line2.clear(); line2.push_back(Point(targetRect.x + targetRect.width - 1, targetRect.y)); line2.push_back(Point(targetRect.x + targetRect.width - 1, targetRect.y + targetRect.height - 1)); //if (intersection(line2, line)) // return true; vector line3; line3.clear(); line3.push_back(Point(targetRect.x, targetRect.y)); line3.push_back(Point(targetRect.x + targetRect.width - 1, targetRect.y)); //if (intersection(line3, line)) // return true; vector line4; line4.clear(); line4.push_back(Point(targetRect.x, targetRect.y + targetRect.height - 1)); line4.push_back(Point(targetRect.x + targetRect.width - 1, targetRect.y + targetRect.height - 1)); //if (intersection(line4, line)) // return true; if (intersection(line1, line) || intersection(line2, line) || intersection(line3, line) || intersection(line4, line)) { return true; } else { return false; } } //判断是否相似度 bool cvMatEQ(const cv::Mat& data1, const cv::Mat& data2) { bool success = true; // check if is multi dimensional if (data1.dims > 2 || data2.dims > 2) { if (data1.dims != data2.dims || data1.type() != data2.type()) { return false; } for (int dim = 0; dim < data1.dims; dim++) { if (data1.size[dim] != data2.size[dim]) { return false; } } } else { if (data1.size() != data2.size() || data1.channels() != data2.channels() || data1.type() != data2.type()) { return false; } } int nrOfElements = data1.total()*data1.elemSize1(); //bytewise comparison of data int cnt = 0; for (cnt = 0; cnt < nrOfElements && success; cnt++) { if (data1.data[cnt] != data2.data[cnt]) { success = false; } } return success; } //寻找是否有rect bool findMap(Rect r, map m) { for (map::iterator mit = m.begin(); mit != m.end(); mit++) { if (r.x == (*mit).second.x && r.y == (*mit).second.y) { return true; break; } if (mit == m.end()) { return false; } } } //截取rect内图片 void HVrectToImage(const IplImage* image, const CvRect rect, IplImage* result) { int imageX, imageY; for (int i = 0; iimageData + result->widthStep*j))[i] = ((uchar*)(image->imageData + image->widthStep*imageY))[imageX]; } } /*---------------------------------------------------------------------------------------------*/ int main(int argc, char*argv[]) { //读取视频 VideoCapture video("C:\\Users\\Administrator\\Desktop\\image\\5.mp4"); //判断视频是否打开 if (!video.isOpened()) return 0; //视频中的第一帧 Mat firstFrame; Mat frame; //读取视频的第一帧 video >> frame; resize(frame, frame, Size(frame.cols / 4, frame.rows / 4)); //复制到firstFrame中 frame.copyTo(firstFrame); //register namedWindow("video", 1); setMouseCallback("video", mouseLineHandler, NULL); //画线 while (!got_line) { firstFrame.copyTo(frame); line(frame, beginPoint, endPoint, Scalar(255, 0, 0), 2); imshow("video", frame); if (waitKey(50) == 'q')//---------很重要 break; } //remove callback setMouseCallback("video", NULL, NULL); Mat mask, maskCp; vector> cnts; Rect maxRect; const double RECT_HW_RATIO = 0.8; // 人体长宽比阈值 const double RECT_AREA_RATIO = 0.005; // 人体占整个图像最小比例阈值 const double RECT_AREA_RATIO2 = 0.01; // 人体占整体图像最大比例阈值 Ptr bgsubtractor = createBackgroundSubtractorMOG2(); bgsubtractor->setHistory(20); bgsubtractor->setVarThreshold(100); bgsubtractor->setDetectShadows(true); int spaceFrames = 0; // 每隔125帧统计一次 const int SPACE_FRAME = 125; int hasPeopleFrameCnt = 0; //const int SPACE_FRAME_ = 125; //vector> Vpoint; vector ivec2; ivec2.push_back(beginPoint); ivec2.push_back(endPoint); int frameCount = 0; //视频继续 for (;;) { video >> frame; resize(frame, frame, Size(frame.cols / 4, frame.rows / 4)); int x0 = frame.cols* 0.3; int y0 = frame.rows *0.33; int x1 = frame.cols *0.9; int y1 = frame.rows *0.9; cv::Point p0 = cv::Point(x0, y0); cv::Point p1 = cv::Point(x1, y1); rectangle(frame, p0, p1, cv::Scalar(0, 255, 0), 5, 8); line(frame, beginPoint, endPoint, Scalar(255, 255, 0), 2); // 背景更新 bgsubtractor->apply(frame, mask, 0.002); // 中值滤波 medianBlur(mask, mask, 3); // 阈值分割,去阴影 threshold(mask, mask, 200, 255, CV_THRESH_BINARY); // 找轮廓 maskCp = mask.clone(); findContours(maskCp, cnts, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); vector boundRect(cnts.size()); //vector yuejie; // 画最大外接矩形 for (int i = 0; i < cnts.size(); i++) { boundRect[i] = boundingRect(cnts[i]); double area = (double)boundRect[i].area(); //cout << area << endl; double rectAreaRatio = (double)boundRect[i].area() / (frame.cols * frame.rows); int bx = boundRect[i].x + boundRect[i].width / 2; int by = boundRect[i].y + boundRect[i].height / 2; bool flag = true; flag = bx > x0 && bxy0 && by RECT_AREA_RATIO && rectAreaRatio < RECT_AREA_RATIO2 && flag) { rectangle(frame, boundRect[i], Scalar(0, 255, 0), 2); if (rect_line_intersection(ivec2, boundRect[i])) { cout << "有物体越线" << endl; } else { cout << "没越线" << endl; } ++hasPeopleFrameCnt; } } ++spaceFrames; imshow("video", frame); if (waitKey(33) == 'q') break; } return 0; }
看完希望对感兴趣的同学有所启发,手打不易,谢谢点赞。