C++ Opencv 视频处理 物体越线 越界 绊线 源码

本篇主要解决物体越线问题,当运行代码时,视频会停在第一帧,这时可以用鼠标划出一条线段,作为越界的标准线。

当画完之后视频自动运行,有行人或者物体运动时会被检测出来并标出外接矩形框,当外接矩形框与画出线段相交时,会显示物体越界或物体越线,本产品用于公共场所的行为规范安全问题。

 

#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;
}

看完希望对感兴趣的同学有所启发,手打不易,谢谢点赞。

你可能感兴趣的:(C++源码)