帧差运动检测和颜色检测(C++)

基于视频的烟火检测

首先,对图像进行预处理:

1.对图像分块,将图像分为24*24的小块

2.对每块图像进行运动检测及颜色检测

然后,使用训练好的神经网络对图像进行分类

分块帧差运动检测

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace cv;

//计算二值图像素大于0的个数
int bSums(Mat src)
{
	int counter = 0;
	//迭代器访问像素点
	Mat_<uchar>::iterator it = src.begin<uchar>();
	Mat_<uchar>::iterator itend = src.end<uchar>();
	for (; it != itend; ++it)
	{
		if ((*it)>0) counter += 1;//二值化后,像素点是0或者255
	}
	return counter;
}
//图像块结构体
struct FraRIO
{
	Mat frameRIO;
	int point_x;
	int point_y;
	bool RIO_flag;

};
//每帧图像分块
vector<FraRIO>  DivFra(Mat &image, int width, int height)
{
	char name = 1;
	int m, n;
	m = image.rows / height;
	n = image.cols / width;
	vector<FraRIO> FraRIO_Out;
	FraRIO temFraRIO;
	for (int j = 0; j<m; j++)
	{
		for (int i = 0; i<n; i++)
		{
			Mat temImage(height, width, CV_8UC3, cv::Scalar(0, 0, 0));//
			Mat imageROI = image(Rect(i*width, j*height, temImage.cols, temImage.rows));//rect(x, y, width, height)选定感兴趣区域
			addWeighted(temImage, 1.0, imageROI, 1.0, 0., temImage);//复制扫描出的边界内数据

			temFraRIO.frameRIO = temImage.clone();
			temFraRIO.point_x = i*width;
			temFraRIO.point_y = j*height;
			FraRIO_Out.push_back(temFraRIO);
		}
	}
	return FraRIO_Out;
}

int main()
{
	//读取视频
	VideoCapture capture("C:/Users/Administrator/Desktop/FireCollect/neg/nonfire_indoor_6.avi");
	if (!capture.isOpened())
		return -1;

	//
	double rate = capture.get(CV_CAP_PROP_FPS);
	int delay = 1000 / rate;

	//定义当前帧和临时帧
	Mat frame, tem_frame;

	//定义前一帧和当前帧分割后的结构体数组
	vector<FraRIO> framePro_RIO;
	vector<FraRIO> frame_RIO;

	bool flag = false;

	namedWindow("image", CV_WINDOW_AUTOSIZE);

	while (capture.read(frame)){
		//对当前帧进行分割,大小24*24
		frame_RIO = DivFra(frame,24,24);

		if (false == flag)
		{
			//当前帧数组赋值前一帧数组
			framePro_RIO = frame_RIO;
			flag = true;
		}
		else
		{
			//
			vector<FraRIO>::iterator it_pro = framePro_RIO.begin();
			vector<FraRIO>::iterator it = frame_RIO.begin();
			//对结构体数组进行遍历
			while (it != frame_RIO.end() && it_pro != framePro_RIO.end())
			{
				//当前帧与前一帧做差,存入临时帧
				absdiff(it->frameRIO, it_pro->frameRIO, tem_frame);
				//彩色图转灰度图
				cvtColor(tem_frame, tem_frame, COLOR_BGR2GRAY);
				//二值化
				threshold(tem_frame, tem_frame, 80, 255, CV_THRESH_BINARY);

				cout << bSums(tem_frame) << endl;
				//找出像素大于0的区块
				if (bSums(tem_frame)>0){
					//画出矩形框
					rectangle(frame, cvPoint(it->point_x, it->point_y), cvPoint(it->point_x+it->frameRIO.cols, it->point_y+it->frameRIO.rows), Scalar(255, 0, 0), 1, 1, 0);//能够实时显示运动物体
				}
				it++;
				it_pro++;
			}
			//
			framePro_RIO = frame_RIO;

			imshow("image", frame);

			waitKey(delay);
		}
	}
	return 0;
}

火焰颜色模型(opencv2_用到YCrCb)

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;


void ImgMean(float& c1, float& c2, float& c3, Mat pImg)
{
	int nPixel = pImg.rows*pImg.cols;	// number of pixels in image
	c1 = 0; c2 = 0; c3 = 0;

	//累加各通道的值
	MatConstIterator_<Vec3b> it = pImg.begin<Vec3b>();
	MatConstIterator_<Vec3b> itend = pImg.end<Vec3b>();

	while (it != itend)
	{
		c1 += (*it)[0];
		c2 += (*it)[1];
		c3 += (*it)[2];
		it++;

	}
	//累加各通道的值

	c1 = c1 / nPixel;
	c2 = c2 / nPixel;
	c3 = c3 / nPixel;
}

int bSums(Mat &src)
{
	int counter = 0;
	//迭代器访问像素点
	Mat_<uchar>::iterator it = src.begin<uchar>();
	Mat_<uchar>::iterator itend = src.end<uchar>();
	for (; it != itend; ++it)
	{
		if ((*it)>0) counter += 1;//二值化后,像素点是0或者255
	}
	return counter;
}
int main(){

	Mat srcImg = imread("G:/fire/ship1.jpg");
	Mat m_pcurFrameYCrCb;
	Mat pImgResult;

	m_pcurFrameYCrCb.create(srcImg.size(), srcImg.type());
	pImgResult.create(srcImg.size(), srcImg.type());
	cvtColor(srcImg, m_pcurFrameYCrCb, CV_BGR2YCrCb);
	//m_pcurFrameYCrCb = srcImg.clone();

	float yy_mean = 0, cr_mean = 0, cb_mean = 0;
	ImgMean(cb_mean, cr_mean, yy_mean, m_pcurFrameYCrCb);
	uchar r = 0, g = 0, b = 0;
	uchar yy = 0, cr = 0, cb = 0;


	for (int i = 0; i<srcImg.rows; i++){
		for (int j = 0; j<srcImg.cols; j++){

			b = srcImg.at<Vec3b>(i, j)[0];
			g = srcImg.at<Vec3b>(i, j)[1];
			r = srcImg.at<Vec3b>(i, j)[2];

			cb = m_pcurFrameYCrCb.at<Vec3b>(i, j)[0];
			cr = m_pcurFrameYCrCb.at<Vec3b>(i, j)[1];
			yy = m_pcurFrameYCrCb.at<Vec3b>(i, j)[2];

			if (r>120 && yy>cb&&cr>cb&&yy>yy_mean && (abs(cb - cr)>40))
				//if (r>12 && r>g && g>b && yy>cb&&cr>cb && cr>cr_mean  && cb<cb_mean && yy>yy_mean && (abs(cb - cr)>40))
			{
				pImgResult.at<Vec3b>(i, j)[0] = 255;
				pImgResult.at<Vec3b>(i, j)[1] = 255;
				pImgResult.at<Vec3b>(i, j)[2] = 255;
			}
			else
			{
				pImgResult.at<Vec3b>(i, j)[0] = 0;
				pImgResult.at<Vec3b>(i, j)[1] = 0;
				pImgResult.at<Vec3b>(i, j)[2] = 0;

			}

		}
	}
	//彩色图转灰度图
	cvtColor(pImgResult, pImgResult, COLOR_BGR2GRAY);
	//二值化
	//threshold(pImgResult, pImgResult, 80, 255, CV_THRESH_BINARY);
	cout << bSums(pImgResult) << endl;
	namedWindow("Color", WINDOW_NORMAL);
	imshow("Color", pImgResult);

	waitKey(0);

	return 0;
}

火焰颜色模型(opencv2_没用到YCrCb_1)

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;


void ImgMean(float& c1, float& c2, float& c3, Mat pImg)
{
	int nPixel = pImg.rows*pImg.cols;	// number of pixels in image
	c1 = 0; c2 = 0; c3 = 0;

	uchar* pData = pImg.data;
	uchar* pcurPixel = pData;
	//累加各通道的值

	for (int y = 0; y< pImg.rows; y++)
	{
		pcurPixel = pData;
		for (int x = 0; x < pImg.cols; x++)
		{
			c1 += pcurPixel[0];
			c2 += pcurPixel[1];
			c3 += pcurPixel[2];
			pcurPixel += 3;
		}
		pData += pImg.step;
	}

	//累加各通道的值

	c1 = c1 / nPixel;
	c2 = c2 / nPixel;
	c3 = c3 / nPixel;
}

int bSums(Mat &src)
{
	int counter = 0;
	//迭代器访问像素点
	Mat_<uchar>::iterator it = src.begin<uchar>();
	Mat_<uchar>::iterator itend = src.end<uchar>();
	for (; it != itend; ++it)
	{
		if ((*it)>0) counter += 1;//二值化后,像素点是0或者255
	}
	return counter;
}
int main(){

	Mat srcImg = imread("G:/fire/ship1.jpg");
	Mat m_pcurFrameYCrCb;
	Mat pImgResult;

	m_pcurFrameYCrCb.create(srcImg.size(), srcImg.type());

	pImgResult.create(srcImg.size(), srcImg.type());
	
	m_pcurFrameYCrCb = srcImg.clone();
	//cvtColor(srcImg, m_pcurFrameYCrCb, CV_BGR2YCrCb);

	uchar* pData = (uchar*)srcImg.data;
	uchar* pDataYCrCb = (uchar*)m_pcurFrameYCrCb.data;

	uchar* pDataResult = (uchar*)pImgResult.data;

	uchar* pcurPixel = pData;
	uchar* pcurPixelYCrCb = pDataYCrCb;
	uchar* pcurPixelResult = pDataResult;

	float yy_mean = 0, cr_mean = 0, cb_mean = 0;


	ImgMean(cb_mean, cr_mean, yy_mean, m_pcurFrameYCrCb);
	uchar r = 0, g = 0, b = 0;
	uchar yy = 0, cr = 0, cb = 0;

	for (int y = 0; y< srcImg.rows; y++)
	{
		pcurPixel = pData + y*srcImg.step;
		pcurPixelYCrCb = pDataYCrCb + y*m_pcurFrameYCrCb.step;
		pcurPixelResult = pDataResult + y* pImgResult.step;

		for (int x = 0; x < srcImg.cols; x++)
		{
			b = pcurPixel[0];
			g = pcurPixel[1];
			r = pcurPixel[2];

			cb = pcurPixelYCrCb[0];
			cr = pcurPixelYCrCb[1];
			yy = pcurPixelYCrCb[2];
			//根据公式判断该点是否符合火焰颜色模型的条件
			if (r>120 && yy>cb&&cr>cb&&yy>yy_mean && (abs(cb - cr)>40))
			{
				//*pcurPixelResult = 255;
				pcurPixelResult[0] = 255;
				pcurPixelResult[1] = 255;
				pcurPixelResult[2] = 255;

			}
			else
			{
				//*pcurPixelResult = 0;
				pcurPixelResult[0] = 0;
				pcurPixelResult[1] = 0;
				pcurPixelResult[2] = 0;
			}
			pcurPixel += 3;
			pcurPixelYCrCb += 3;
			//pcurPixelResult++;
			pcurPixelResult += 3;
		}
	}

	//彩色图转灰度图
	cvtColor(pImgResult, pImgResult, COLOR_BGR2GRAY);
	//二值化
	//threshold(pImgResult, pImgResult, 80, 255, CV_THRESH_BINARY);
	//cout << bSums(pImgResult) << endl;
	namedWindow("Color", WINDOW_NORMAL);
	imshow("Color", pImgResult);

	waitKey(0);

	return 0;
}

main.cpp

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace cv;

//计算二值图像素大于0的个数
int bSums(Mat src)
{
	int counter = 0;
	//迭代器访问像素点
	Mat_<uchar>::iterator it = src.begin<uchar>();
	Mat_<uchar>::iterator itend = src.end<uchar>();
	for (; it != itend; ++it)
	{
		if ((*it)>0) counter += 1;//二值化后,像素点是0或者255
	}
	return counter;
}
//图像块结构体
struct FraRIO
{
	Mat frameRIO;
	int point_x;
	int point_y;
	bool RIO_flag;

};
//每帧图像分块
vector<FraRIO>  DivFra(Mat &image, int width, int height)
{
	char name = 1;
	int m, n;
	m = image.rows / height;
	n = image.cols / width;
	vector<FraRIO> FraRIO_Out;
	FraRIO temFraRIO;
	for (int j = 0; j<m; j++)
	{
		for (int i = 0; i<n; i++)
		{
			Mat temImage(height, width, CV_8UC3, cv::Scalar(0, 0, 0));//
			Mat imageROI = image(Rect(i*width, j*height, temImage.cols, temImage.rows));//rect(x, y, width, height)选定感兴趣区域
			addWeighted(temImage, 1.0, imageROI, 1.0, 0., temImage);//复制扫描出的边界内数据

			temFraRIO.frameRIO = temImage.clone();
			temFraRIO.point_x = i*width;
			temFraRIO.point_y = j*height;
			FraRIO_Out.push_back(temFraRIO);
		}
	}
	return FraRIO_Out;
}

void ImgMean(float& c1, float& c2, float& c3, Mat pImg)
{
	int nPixel = pImg.rows*pImg.cols;	// number of pixels in image
	c1 = 0; c2 = 0; c3 = 0;

	//累加各通道的值
	MatConstIterator_<Vec3b> it = pImg.begin<Vec3b>();
	MatConstIterator_<Vec3b> itend = pImg.end<Vec3b>();

	while (it != itend)
	{
		c1 += (*it)[0];
		c2 += (*it)[1];
		c3 += (*it)[2];
		it++;

	}
	//累加各通道的值

	c1 = c1 / nPixel;
	c2 = c2 / nPixel;
	c3 = c3 / nPixel;
}

Mat ColorDet(Mat srcImg){
	Mat m_pcurFrameYCrCb;
	Mat pImgResult;

	m_pcurFrameYCrCb.create(srcImg.size(), srcImg.type());
	pImgResult.create(srcImg.size(), srcImg.type());
	//cvtColor(srcImg, m_pcurFrameYCrCb, CV_BGR2YCrCb);
	m_pcurFrameYCrCb = srcImg.clone();

	float yy_mean = 0, cr_mean = 0, cb_mean = 0;
	ImgMean(cb_mean, cr_mean, yy_mean, m_pcurFrameYCrCb);
	uchar r = 0, g = 0, b = 0;
	uchar yy = 0, cr = 0, cb = 0;


	for (int i = 0; i<srcImg.rows; i++){
		for (int j = 0; j<srcImg.cols; j++){

			b = srcImg.at<Vec3b>(i, j)[0];
			g = srcImg.at<Vec3b>(i, j)[1];
			r = srcImg.at<Vec3b>(i, j)[2];

			cb = m_pcurFrameYCrCb.at<Vec3b>(i, j)[0];
			cr = m_pcurFrameYCrCb.at<Vec3b>(i, j)[1];
			yy = m_pcurFrameYCrCb.at<Vec3b>(i, j)[2];

			if (r>120 && yy>cb&&cr>cb&&yy>yy_mean && (abs(cb - cr)>40))
				//if (r>12 && r>g && g>b && yy>cb&&cr>cb && cr>cr_mean  && cb<cb_mean && yy>yy_mean && (abs(cb - cr)>40))
			{
				pImgResult.at<Vec3b>(i, j)[0] = 255;
				pImgResult.at<Vec3b>(i, j)[1] = 255;
				pImgResult.at<Vec3b>(i, j)[2] = 255;

			}
			else
			{
				pImgResult.at<Vec3b>(i, j)[0] = 0;
				pImgResult.at<Vec3b>(i, j)[1] = 0;
				pImgResult.at<Vec3b>(i, j)[2] = 0;

			}

		}
	}
	//彩色图转灰度图
	cvtColor(pImgResult, pImgResult, COLOR_BGR2GRAY);

	return pImgResult;
}

int main()
{
	int interval = 0;
	// /root/zhangsong/fairworks/github/darknet-master/fireworks/data/TestVideo_5.mp4
	// /root/zhangsong/fairworks/github/darknet-master/data/zs_test_video/CA28_S20201015133001_E20201015163000_005710781-005851374.mp4
	// /root/zhangsong/fairworks/github/darknet-master/fireworks/data/fog/longgang-07-57-54_08-03-59_0-1.mp4
	// /root/zhangsong/fairworks/github/darknet-master/fireworks/data/S1090009-12.MP4
	// /root/zhangsong/fairworks/github/darknet-master/fireworks/data/20200406082838_4.mp4  fireworks/data/G92X211K400_CVR_10-03-00_10-06-59_0.mp4  真实货车冒烟数据
	//读取视频
	VideoCapture capture("/root/zhangsong/fairworks/github/darknet-master/data/zs_test_video/CA28_S20201015133001_E20201015163000_005710781-005851374.mp4");
	if (!capture.isOpened())
		return -1;

	//
	double rate = capture.get(CV_CAP_PROP_FPS);
	int delay = 1000 / rate;

	//定义当前帧和临时帧
	Mat frame, tem_frame;

	//定义前一帧和当前帧分割后的结构体数组
	vector<FraRIO> framePro_RIO;
	vector<FraRIO> frame_RIO;

	bool flag = false;

	namedWindow("image", CV_WINDOW_AUTOSIZE);

	while (capture.read(frame)){
		interval++;
		if(interval%3 != 0)
		{
			continue;
		}
		//对当前帧进行分割,大小24*24
		frame_RIO = DivFra(frame, 15, 15);

		if (false == flag)
		{
			//当前帧数组赋值前一帧数组
			framePro_RIO = frame_RIO;
			flag = true;
		}
		else
		{
			//
			vector<FraRIO>::iterator it_pro = framePro_RIO.begin();
			vector<FraRIO>::iterator it = frame_RIO.begin();
			//对结构体数组进行遍历
			while (it != frame_RIO.end() && it_pro != framePro_RIO.end())
			{
				//当前帧与前一帧做差,存入临时帧
				absdiff(it->frameRIO, it_pro->frameRIO, tem_frame);
				//彩色图转灰度图
				cvtColor(tem_frame, tem_frame, COLOR_BGR2GRAY);
				//二值化
				threshold(tem_frame, tem_frame, 8, 255, CV_THRESH_BINARY);

				//cout << bSums(ColorDet(it->frameRIO)) << endl;
				//tem_frame = tem_frame & ColorDet(it->frameRIO);

				//cout << bSums(tem_frame) << endl;

				//找出像素大于0的区块
				if (bSums(tem_frame)>150){
					//画出矩形框
					rectangle(frame, cvPoint(it->point_x, it->point_y), cvPoint(it->point_x + it->frameRIO.cols, it->point_y + it->frameRIO.rows), Scalar(255, 0, 0), 4, 8, 0);//能够实时显示运动物体
				}
				it++;
				it_pro++;
			}
			//
			framePro_RIO = frame_RIO;

        	cv::Size show_size = cv::Size((int)(640), (int)(360));
        	cv::Mat show_image;
        	cv::resize(frame, show_image, show_size);

			imshow("image", show_image);

			waitKey(delay);
			//waitKey(1);
		}
	}
	return 0;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值