作者:qq_27569955
上两篇博文给大家分别介绍了在火焰检测中常用的两种颜色判据——RGB判据和HSI判据,这一篇博文给大家展示一下它们两个单纯结合的效
果,然后介绍一个更强大的结合算法,能够很好地分割出火焰区域。在下篇博文将会在RGB判据以及HSI判据的基础上分别添加更加严格的约束条件,
使得不合理的区域进一步缩小。
首先,我们尝试一下简单地用上两篇介绍的判据分别提取出来的区域进行与运算,看看效果有没有改善。
这是我们的测试原图:
这是仅用RGB判据后得出的火焰区域:
很明显,得出来的是一个实心的区域,说明RGB判据用来提取完整区域是挺有效果的。
再来看看仅用HSI判据后得出的火焰区域:
这次得出来的就不是一个区域了,而是一个火焰的轮廓,上一篇博文也曾经说过,如果想要得出一个区域,就要适当修改输入的三组阈值参数值,现在
假设我们需要的是火焰的轮廓而不是实心区域,所以仍保留这个效果。
最后看看两者的与运算,看看有没有什么变化:
我们仔细观察一下,可以发现火焰区域变得更细了,比仅用HSI判据实现的效果更加柔和,看上去更加舒服。
现在我们不再单纯地结合两个颜色判据,而是在原有的RGB判据中添加HSI判据的变种,形成一个强大的颜色判据。该结合判据的算法如下:
保留RGB判据:
R > R_avg AND
R >= G >= B
添加新的HSI约束条件:
S > 0.2 AND
S > (255 - R) / 20 AND
S >= ((255 - R)*ST / RT
其中,ST为饱和度阈值,参考范围是55~65;RT为红色分量阈值,参考范围是115~135。
很明显,我们可以看出结合判据既基本上保留了RGB判据,又保留了HSI判据的可互动修改参数的特点,理论上会比单独使用或单纯结合的效
果要好。
下面给出结合判据的函数代码:
int ProcessColorModel(IplImage *RGBimg,IplImage*dst){ if(RGBimg == NULL || dst == NULL){ printf("func ProcessColorModel() Error:\n"); printf("RGBimg == NULL || dst == NULL\n"); return -1;
} if(RGBimg->nChannels != 3 || dst->nChannels != 1){ printf("func ProcessColorModel() Error:\n"); printf("RGBimg->nChannels != 3 || dst->nChannels != 1\n"); return -1;
}
CvSize size = cvGetSize(RGBimg);
IplImage * pImgFire = cvCreateImage(size, 8, 3);
cvSet(pImgFire, cvScalar(0, 0, 0)); int RedThreshold = 115; //115~135
int SaturationThreshold = 55; //55~65
for (int j = 0; j < RGBimg->height; j++){ for (int i = 0; i < RGBimg->widthStep; i += 3){
uchar B = (uchar)RGBimg->imageData[j*RGBimg->widthStep + i + 0];
uchar G = (uchar)RGBimg->imageData[j*RGBimg->widthStep + i + 1];
uchar R = (uchar)RGBimg->imageData[j*RGBimg->widthStep + i + 2];
uchar maxv = max(max(R, G), B);
uchar minv = min(min(R, G), B);
double S = (1 - 3.0*minv / (R + G + B)); //生成二值图 if (R > RedThreshold && R >= G && G >= B && S > 0.20 && S > (255 - R) / 20 && S >= ((255 - R)*SaturationThreshold / RedThreshold)){
pImgFire->imageData[j*RGBimg->widthStep + i + 0] = 255;
pImgFire->imageData[j*RGBimg->widthStep + i + 1] = 255;
pImgFire->imageData[j*RGBimg->widthStep + i + 2] = 255;
} else{
pImgFire->imageData[j*RGBimg->widthStep + i + 0] = 0;
pImgFire->imageData[j*RGBimg->widthStep + i + 1] = 0;
pImgFire->imageData[j*RGBimg->widthStep + i + 2] = 0;
}
}
}
cvCvtColor(pImgFire, dst, CV_BGR2GRAY);
cvReleaseImage(&pImgFire); return 0;
}
- 1
由于只需要使用S分量,不需要使用H和I分量,所以在此并不需要单独写颜色模型转换函数,而只需要在函数里面计算S分量即可。
最后我们看看效果如何:
(为了证实算法的强大性,我们来验证两组有干扰物的图片,读者有兴趣可自行验证以前我们使用的那幅图片,在这就不演示了)
①:原图
这是一幅有建筑物干扰的图片,建筑物有一点偏向火焰颜色的趋势,那么我们的算法能不能正确提取火焰区域而不
显然,基本上没有圈出建筑物,但仍存在一点噪声干扰,读者可以使用我们最开始介绍的图像预处理里面的方法来去除孤立点。
②:原图
这是一幅有其他光源干扰的图片,并且火焰的区域很多,那么提取效果如何呢?
关注【OpenCV学习交流】
长按或者扫描下面二维码即可关注