火灾检测算法(基于opencv)

记录西安电子科技大学星火杯软件赛道一等奖(大一)

include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;
bool detectSmoke(Mat frame) {
    // 实现烟雾检测算法
    // 使用简单的颜色阈值
     // 转换为HSV颜色空间
    Mat hsv;
    cvtColor(frame, hsv, COLOR_BGR2HSV);

    cv::Scalar lowerBound(0, 50, 100); // 请根据实际情况调整下限
    cv::Scalar upperBound(10, 255, 255); // 请根据实际情况调整上限


    // 通过颜色阈值获取烟雾区域的二值图像
    Mat mask;
    inRange(hsv, lowerBound, upperBound, mask);

    // 使用形态学操作进行噪音过滤
    Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(5, 5));
    morphologyEx(mask, mask, MORPH_OPEN, kernel);
    morphologyEx(mask, mask, MORPH_CLOSE, kernel);

    // 计算二值图像中白色像素的数量
    int whitePixels = countNonZero(mask);
    putText(frame, "White Pixels: " + std::to_string(whitePixels), Point(10, 30), FONT_HERSHEY_SIMPLEX, 1, Scalar(255, 255, 255), 2);

    // 根据实际情况调整阈值
    return whitePixels > 5000;


}

bool detectMotion(Mat prevFrame, Mat currentFrame) {
    // 运动检测算法
    // 使用帧差
    Mat diff;
    absdiff(prevFrame, currentFrame, diff);

    Mat grayDiff;
    cvtColor(diff, grayDiff, COLOR_BGR2GRAY);

    Mat thresholdDiff;
    threshold(grayDiff, thresholdDiff, 30, 255, THRESH_BINARY);
     putText(currentFrame, "motion level: " + std::to_string(countNonZero(thresholdDiff)), Point(10, 60), FONT_HERSHEY_SIMPLEX, 1, Scalar(255, 255, 255), 2);

    return countNonZero(thresholdDiff) > 4000;  // 根据实际情况调整阈值
}

bool detectLightChange(Mat prevFrame, Mat currentFrame) {
    // 的光照变化检测算法
    // 使用平均强度差异
    Mat diff;
    absdiff(prevFrame, currentFrame, diff);

    Mat grayDiff;
    cvtColor(diff, grayDiff, COLOR_BGR2GRAY);
     putText(currentFrame, "light level " + std::to_string(mean(grayDiff)[0]), Point(10, 90), FONT_HERSHEY_SIMPLEX, 1, Scalar(255, 255, 255), 2);

    return mean(grayDiff)[0] > 2;  // 根据实际情况调整阈值
}

void drawSmokeRegion(Mat& frame, std::vector<std::vector<Point>>& contours,double minContourAreaThreshold) {

        for (const auto& contour : contours) {
 double area = contourArea(contour);

         if (area > minContourAreaThreshold) {
            std::vector<Point> hull;
            convexHull(contour, hull);
            drawContours(frame, std::vector<std::vector<Point>>{hull}, 0, Scalar(0, 0, 255), 3);  // 橙红色
    }
}
}
int main()
{
        double minContourAreaThreshold = 300.0;  // 设置阈值

        int smoke,light,motion;
        smoke=0;
        light =0;
        motion =0;
        int sos =0;
    VideoCapture capture("/home/a/Desktop/123.mp4");
    //测试视频路径
    ///home/a/Desktop/IMG_2960.MP4
    ///home/a/Desktop/RPReplay_Final1701363220.MP4
    ///home/a/Desktop/b4412ebf2a608091ca2bbbf005a4e304.mp4
    ///home/a/Desktop/f142649fca7338a9a5f821069df06993_raw.mp4
///home/a/Desktop/eca471f4a7b82dd6866cdb9162536eca.mp4
///home/a/Desktop/e007a752da82088104d98762b9f86bbf_raw.mp4
///home/a/Desktop/e1dd4b101a51f8248e0ee46ec0990efa_raw.mp4
///home/a/Desktop/bb0bbb3bdbf49cdd6fdf0789e513a1a1_raw.mp4
///home/a/Desktop/b4412ebf2a608091ca2bbbf005a4e304_raw.mp4
///home/a/Desktop/59ef339385022b76dda6bf13223c.mp4

///home/a/Desktop/26c24abe36157021d3628191229c213d_raw.mp4

    if (!capture.isOpened()) {
        std::cout << "Error: Couldn't open the video file." << std::endl;
        return -1;
    }

    Mat prevFrame;
    capture.read(prevFrame);

    while (capture.isOpened()) {
        Mat currentFrame;
        Mat currentFrame1;
        capture.read(currentFrame);



        if (currentFrame.empty()) {
            break;
        }


    Mat hsv;
    Mat image = currentFrame.clone();
    resize(image, image, Size(), 0.5, 0.5);//!!!!!!!!
    cvtColor(image, hsv, COLOR_BGR2HSV);

    cv::Scalar lowerBound(0,50,100); // 请根据实际情况调整下限
    cv::Scalar upperBound(10,255, 255); // 请根据实际情况调整上限


    // 通过颜色阈值获取烟雾区域的二值图像
    Mat mask;
    inRange(hsv, lowerBound, upperBound, mask);
     // 查找橙红色区域的轮廓
    std::vector<std::vector<Point>> contours;
 findContours(mask, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
      Mat smokeRegion = currentFrame.clone();
      resize(smokeRegion,smokeRegion, Size(), 0.5, 0.5);
       drawSmokeRegion(smokeRegion, contours,minContourAreaThreshold);
        imshow("Smoke Region", smokeRegion);



        // 烟雾检测
        if (detectSmoke(currentFrame)) {
            std::cout << "have smoke" << std::endl;
            smoke++;

        }
        // 运动检测
        if (detectMotion(prevFrame, currentFrame)) {
            std::cout << "Motion Detection: Anomalous Motion Occurred!" << std::endl;
            motion++;
        }

        // 光照变化检测
        if (detectLightChange(prevFrame, currentFrame)) {
            std::cout << "Light Change Detection: Possible Fire Occurred!" << std::endl;
            light++;
        }
        if(detectSmoke(currentFrame)&&detectMotion(prevFrame, currentFrame)&&detectLightChange(prevFrame, currentFrame))
        {
                std::cout<<"SOS-SOS"<<std::endl;
                sos++;
        }


        // 显示当前帧
        imshow("Video Frame", currentFrame);

        // 更新前一帧
        prevFrame = currentFrame.clone();



        // 按 'q' 键退出循环
        if (waitKey(20) == 'q') {
            break;
        }
    }

    std::ofstream outputFile("huozai.txt");
    if (outputFile.is_open()) {
        // 将文本内容写入文件
        outputFile << "<<data数据>>"<<"\n";
        outputFile << "smoke烟雾监测等级(次数):"<<smoke<<"\n";
        outputFile << "light光感变化程度:"<<light<<"\n";
        outputFile <<"motion图面运动变化程度:"<<motion<<"\n";
        outputFile<<"SOS-SOS火灾可信程度等级:"<<sos<<"\n";
       if(sos>10&&sos<20)
    {
        outputFile << "%95火灾可信度"<<"\n";
    }
       else if(sos>=5&&sos<10)  outputFile << "%70火灾可信度"<<"\n";
       else if(sos>=20)  outputFile << "%99火灾可信度"<<"\n";
       else if(sos==0) outputFile << "%0火灾可信度"<<"\n";
       else outputFile << "%50火灾可信度"<<"\n";

       outputFile<<"检测依据:烟雾监测等级,光感变化程度,图面运动变化程度,为火灾的基本监测目标,三者以科学关系并满足一定情况的条件下,>会对应产生SOS-SOS火灾可信程度,以此测算火灾可能度"<<"\n";

        // 关闭文件
        outputFile.close();
  std::cout << "文本写入完成。" << std::endl;
    } else {
        std::cout << "无法打开文件。" << std::endl;
    }
    // 释放资源
    capture.release();
    destroyAllWindows();

    return 0;
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值