-
-
Save arasharchor/cdcd5521b87eb84b0558b1685f270d2e to your computer and use it in GitHub Desktop.
Fire detection algorithm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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