Skip to content

Instantly share code, notes, and snippets.

@arasharchor
Forked from andrew-smith/DetectFire.cpp
Created August 21, 2016 22:22
Show Gist options
  • Save arasharchor/cdcd5521b87eb84b0558b1685f270d2e to your computer and use it in GitHub Desktop.
Save arasharchor/cdcd5521b87eb84b0558b1685f270d2e to your computer and use it in GitHub Desktop.
Fire detection algorithm
#include "stdafx.h"
/*
// configs
//image to load (will not load if USING_VIDEO = true)
#define IMAGE_NAME "fire2.jpg"
//video to load
#define VIDEO_NAME "flamethrower.mp4"
//video:
//candle.avi || gunfire.avi || news_fire.mp4 || fireworks.mp4 || street_explosion.mp4 || challenger_crash.mp4
//tunnel_fire.mp4 || bush_fire.mp4 || flamethrower.mp4
//set to true if it should display a video, false if it should display an image
#define USING_VIDEO true
*/
//set to true to play video, false to advance frame by frame (spacebar)
#define PLAY_VIDEO true
//true to pick up white as a flame, false if not
#define DETECT_WHITE true
//main IPLimage to use
IplImage* image;
//processed image
IplImage* processedImage;
//tmp image to use (backup)
IplImage* tmpImage;
int min(int a, int b)
{
return (a > b) ? (b) : (a);
}
int min3(int a, int b, int c)
{
return (min(min(a, b), c));
}
int max(int a, int b)
{
return (min(a, b) == b) ? (a) : (b);
}
int max3(int a, int b, int c)
{
return (max(max(a, b), c));
}
float rgb2h(int r, int g, int b)
{
double maxC = b;
if (maxC < g) maxC = g;
if (maxC < r) maxC = r;
double minC = b;
if (minC > g) minC = g;
if (minC > r) minC = r;
double delta = maxC - minC;
double V = maxC;
double S = 0;
double H = 0;
if (delta == 0)
{
H = 0;
S = 0;
}
else
{
S = delta / maxC;
double dR = 60*(maxC - r)/delta + 180;
double dG = 60*(maxC - g)/delta + 180;
double dB = 60*(maxC - b)/delta + 180;
if (r == maxC)
H = dB - dG;
else if (g == maxC)
H = 120 + dR - dB;
else
H = 240 + dG - dR;
}
if (H<0)
H+=360;
if (H>=360)
H-=360;
return H;
}
#define MAX_H 360.0
#define MAX_I 255.0
#define MAX_S 1.0
void YCbCrThreshold()
{
for(int i=0; i<image->height; i++)
{
for(int j=0; j<image->width; j++)
{
bool isFire = false;
float bT = ((uchar *)(processedImage->imageData + i*processedImage->widthStep))[j*processedImage->nChannels + 0]; // B
float gT = ((uchar *)(processedImage->imageData + i*processedImage->widthStep))[j*processedImage->nChannels + 1]; // G
float rT = ((uchar *)(processedImage->imageData + i*processedImage->widthStep))[j*processedImage->nChannels + 2]; // R
float b = bT/255, g = gT/255, r = rT/255;
float y = 0.299 * r + 0.587 * g + 0.114 * b;
float cB = -0.168736 * r + -0.331264 * g + 0.500 * b;
float cR = 0.500 * r + -0.418688 * g + -0.081312 * b;
isFire = (y >= cR >= cB);
if(isFire)
{
float crcb = cR - cB;
float ycb = y - cB;
isFire = !(
(crcb >= -0.1 && ycb >= -0.1 && ycb <= 0.3) ||
(crcb >= 0 && crcb <= 0.4 && ycb >= 0 && ycb <= 0.8)
);
}
isFire = isFire && !(cR - cB > -0.1 && y - cB > -0.1 && y - cB <= 0.6);
if(isFire)
{
((uchar *)(processedImage->imageData + i*processedImage->widthStep))[j*processedImage->nChannels + 0] = bT; // B
((uchar *)(processedImage->imageData + i*processedImage->widthStep))[j*processedImage->nChannels + 1] = gT; // G
((uchar *)(processedImage->imageData + i*processedImage->widthStep))[j*processedImage->nChannels + 2] = rT; // R
}
else
{
((uchar *)(processedImage->imageData + i*processedImage->widthStep))[j*processedImage->nChannels + 0] = 0; // B
((uchar *)(processedImage->imageData + i*processedImage->widthStep))[j*processedImage->nChannels + 1] = 0; // G
((uchar *)(processedImage->imageData + i*processedImage->widthStep))[j*processedImage->nChannels + 2] = 0; // R
}
}
}
}
#define RED_THRESHOLD 120
#define MIN_WHITE 180
void redThreshold()
{
for(int i=0; i<image->height; i++)
{
for(int j=0; j<image->width; j++)
{
bool isFire = false;
int b = ((uchar *)(image->imageData + i*image->widthStep))[j*image->nChannels + 0]; // B
int g = ((uchar *)(image->imageData + i*image->widthStep))[j*image->nChannels + 1]; // G
int r = ((uchar *)(image->imageData + i*image->widthStep))[j*image->nChannels + 2]; // R
//find max value and check if it is red
if( (r > b && r > g))
{
//check if red is over a threshold
if( r > RED_THRESHOLD)
{
isFire = true;
}
}
//check for white area, because fire could be white
if(DETECT_WHITE && r > MIN_WHITE && g > MIN_WHITE && b > MIN_WHITE)
isFire = true;
if(isFire)
{
((uchar *)(processedImage->imageData + i*processedImage->widthStep))[j*processedImage->nChannels + 0] = b; // B
((uchar *)(processedImage->imageData + i*processedImage->widthStep))[j*processedImage->nChannels + 1] = g; // G
((uchar *)(processedImage->imageData + i*processedImage->widthStep))[j*processedImage->nChannels + 2] = r; // R
}
}
}
}
CvSeq* drawContourSubtree(CvSeq* contour, int level)
{
if (contour == NULL) return NULL;
// iterate through each sibling
while (contour != NULL)
{
// change the colour of contour depending on level in tree
int brightness = (level+1);
//CvScalar externalColour = CV_RGB(brightness, 255, 0);
//CvScalar holeColour = CV_RGB(brightness, 0, 255);
CvScalar colour = CV_RGB(255, 0, 0);
// draw external/hole parts of this contour in specified colour
cvDrawContours(image, contour, colour, colour, 0, 3, 8, cvPoint(0,0));
if (contour->v_next != NULL) // contour has a child
drawContourSubtree(contour->v_next, level+1);
contour = contour->h_next; // move along to next sibling
}
}
void doCanny()
{
IplImage* greyImage = cvCreateImage(cvGetSize(image),IPL_DEPTH_8U,1);
tmpImage = cvCreateImage(cvGetSize(image),IPL_DEPTH_8U,1);
cvCvtColor(processedImage, greyImage, CV_BGR2GRAY);
//gets canny edges
cvCanny(greyImage, tmpImage, 20, 180, 3);
//attempt to find contours
CvMemStorage* storage = cvCreateMemStorage(0); //dynamic size
CvSeq* contour = NULL; // first contour sibling
int numContours = cvFindContours(tmpImage, storage, &contour, sizeof(CvContour), CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));
//save pointer
CvSeq* tmpContour = contour;
drawContourSubtree(contour, 0);
cvReleaseImage(&greyImage);
//cvReleaseImage(&tmpImage);
cvReleaseMemStorage(&storage);
}
void findFire()
{
redThreshold();
YCbCrThreshold();
doCanny();
}
int main(int argc, char** argv)
{
if(argc < 3)
{
printf("Usage: DetectFire.exe -i|-v [filename]\nExiting...\n");
return -1;
}
*argv++; //first is name of this file
char* loadSwitch = *argv++;
char* IMAGE_NAME = *argv++;
bool USING_VIDEO = (loadSwitch[1] == 'v');
char* filename = IMAGE_NAME;
char* windowNameO = "Original Image";
char* windowNameP = "Processed Image";
cvNamedWindow(windowNameO, CV_WINDOW_AUTOSIZE);
cvNamedWindow(windowNameP, CV_WINDOW_AUTOSIZE);
if(USING_VIDEO)
{
CvCapture* capture = cvCaptureFromFile(IMAGE_NAME);
if(!capture)
{
printf("!!! cvCaptureFromAVI failed (file not found?)\n");
return -1;
}
if(!cvGrabFrame(capture))
{
printf("Error loading video\n");
return -1;
}
int fps = ( int )cvGetCaptureProperty( capture, CV_CAP_PROP_FPS );
int keyVal = 0;
while(cvGrabFrame(capture) && keyVal != VK_ESCAPE) // capture a frame
{
image = cvRetrieveFrame(capture);
processedImage = cvCreateImage(cvSize(image->width, image->height), image->depth, image->nChannels);
//zero processed image
cvZero(processedImage);
findFire();
cvShowImage(windowNameO, image);
cvShowImage(windowNameP, processedImage);
if(PLAY_VIDEO)
keyVal = cvWaitKey(1000 / fps);
else
keyVal = cvWaitKey(0); // blocking
cvReleaseImage(&processedImage);
}
cvReleaseCapture(&capture);
}
else
{
image = cvLoadImage(filename);
processedImage = cvCreateImage(cvSize(image->width, image->height), image->depth, image->nChannels);
cvZero(processedImage);
if (image == NULL)
{
printf("Unable to load image from file %s\n", filename);
return -1;
}
findFire();
cvShowImage(windowNameO, image);
cvShowImage(windowNameP, processedImage);
cvWaitKey(0); // blocking
cvReleaseImage(&image);
cvReleaseImage(&processedImage);
}
cvDestroyWindow(windowNameO);
cvDestroyWindow(windowNameP);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment