关闭

基于OpenCV的火焰检测(二)——RGB颜色判据

575人阅读 评论(0) 收藏 举报
分类:
 上文跟大家分享了在做火焰检测中常用到的图像预处理方法,从这一篇博文开始,我将向大家介绍如何一步一步地检测出火焰区域。火焰提取要用
到很多判据,今天我要向大家介绍的是最简单的但是很有效的判据——RGB判据。

    在介绍这个判据之前,博主首先给大家简单介绍一下RGB模型。根据三基色原理,用基色光单位来表示光的量,则在RGB颜色空间,任意色光F都可
以用R、G、B三色不同分量的相加混合而成:

                                    F=r[R]+g[G]+b[B]

    当三基色分量都为0(最弱)时混合为黑色光;当三基色分量都为k(最强)时混合为白。改变了F的坐标值,也即改变了F的色值。

RGB立体彩色模型

    人眼的视网膜上有两类感光器:锥状体和杆状体。锥状体主要位于视网膜的中间部分,称之为中央凹,且对颜色高度敏感,称为白昼视觉或亮视觉;
杆状体分布面积较大,用来给出视野内的一般的总体图像,没有彩色感觉,而对低照明度敏感,称为微光视觉或暗视觉。由于锥状体对红、绿、蓝三种
颜色的光很敏感,因此一般用于人眼观看的颜色模型是RGB模型。一般来说,无论是在网上下载的图片或视频,还是从摄像机得来的录像,都是RGB
模型。所以,我们从网上下载了一幅火焰图像,不用进行任何的颜色模型转换就可以使用RGB颜色判据来提取区域。

    对于普通的火焰来说,它的红色分量和绿色分量会很大,并且绿色分量会大于蓝色分量,所以我们设下的简单判据是:
                    R > R_avg    AND
                    G > G_avg    AND
                    R > G > B
    其中,R_avg为红色分量的均值。
    在OpenCV1.0中实现很简单,下面先摆出代码:
int cvBGR_CHK(IplImage*img_bgr, IplImage*bgr_chk){
    if (img_bgr == NULL || bgr_chk == NULL){
        printf("func cvBGR_CHK Error:\n");
        printf("img_bgr == NULL || bgr_chk == NULL\n");
        return -1;
    }
    if (img_bgr->nChannels != 3 || bgr_chk->nChannels != 1){
        printf("func cvBGR_CHK Error:\n");
        printf("img_bgr->nChannels != 3 || bgr_chk->nChannels != 1\n");
        return -1;
    }
    CvScalar avg;
    avg = cvAvg(img_bgr);
    CvSize size = cvGetSize(img_bgr);
    IplImage*R = cvCreateImage(size, 8, 1);
    IplImage*G = cvCreateImage(size, 8, 1);
    IplImage*B = cvCreateImage(size, 8, 1);
    IplImage*tmp1 = cvCreateImage(size, 8, 1);
    IplImage*tmp2 = cvCreateImage(size, 8, 1);
    cvSplit(img_bgr, B, G, R, NULL);
    cvCmpS(R, avg.val[2], tmp1, CV_CMP_GT);
    cvCmpS(G, avg.val[1], tmp2, CV_CMP_GT);
    cvMul(tmp1, tmp2, tmp1);
    cvCmp(R, G, tmp2, CV_CMP_GT);
    cvCmp(G, B, G, CV_CMP_GT);
    cvMul(tmp2, G, tmp2);
    cvMul(tmp1, tmp2, tmp1);
    cvConvertScale(tmp1, bgr_chk, 1.0 / 255);
    cvReleaseImage(&R);
    cvReleaseImage(&G);
    cvReleaseImage(&B);
    cvReleaseImage(&tmp1);
    cvReleaseImage(&tmp2);

    return 0;
}
   函数cvBGR_CHK的功能是实现图像的RGB检测,把符合RGB判据的素点置为1,否则置为0,返回的是只有0和1的二值化模板。

    对于写代码的习惯,博主在这里说一下闲话。有些人可能觉得上面函数的格式有点奇怪,特别是返回值,有什么卵用?我的C++老师曾经说过,在做
项目的时候,较为复杂的函数一般不要把返回值作为输出结果。什么意思呢?众所周知,函数返回值只有一个,若想返回两个值或者更多个,用这种
方法就行不通了。对于返回两个或更多个值的函数,在C语言中在输入变量后面,这样就可以轻轻松松地输出两个值。那么返回值不就可以写出void
型的吗?我们的确可以使用void,但是你们想一下,在一个大项目中,往往不止一个函数,那如果运行起来报错了,那么应该怎么找错呢?用断点找?
定位到具体函数要花一定的时间;用编译器自带的检错工具?往往输出并没有什么卵用的信息。如果我们在每个函数里面设定一个对输入输出变量的异
常情况进行自动报错的功能,就会大大简化查错的程序。比如说,在上面的函数中,把检错语句屏蔽掉,我分配给输出变量的内存有三个通道,那么函
数执行肯定会报错,那么我们可不可以简简单单地从系统报错的信息中解决问题呢?首先,我们先运行一把,看看报错信息是啥。

    Unhandled exception at 0x75D3D3CF in FireDectect.exe: Microsoft C++ exception: cv::Exception at memory location 0x0023F3A8.

    有谁可以看出是哪里出了问题吗?反正我不能。再点一下“中断”按钮有木有好的提示?

按了中断之后的弹出内容

    ……什么鬼?
    所以说,返回简单的错误信息很重要吧。如果取消屏蔽,那么就会输出:

func cvBGR_CHK Error:
img_bgr->nChannels != 3 || bgr_chk->nChannels != 1

    那我们可以很快解决木有?
    所以,博主做项目的时候都会采用这种习惯来写函数,这样会大大节省查找低级错误的时间。
    闲话就说到这里,下面我们来检测一下图片看看效果如何:

原图 
运行后的图像

    更多的检测就不在这里重复了,或者有些情况效果不是很好,但要记住,这只是众多判据的其中一个,我们可以两三个判据结合来更精确地提
取区域,这就是以后要分享的东西了。
    今天就分享到这里~欢迎大家多来评论,来找出博主可能存在的错误,希望能和各位图像爱好者共同成长~以后更新会更频繁,大家要继续关注噢~
那么我们下次见~

    下文预告:基于OpenCV的火焰检测(三)——HSI颜色判据
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:194590次
    • 积分:3708
    • 等级:
    • 排名:第9755名
    • 原创:145篇
    • 转载:248篇
    • 译文:0篇
    • 评论:9条
    博客专栏
    最新评论