基于OpenCV的火焰检测(三)——HSI颜色判据
上文向大家介绍了如何用最简单的RGB判据来初步提取火焰区域,现在我要给大家分享的是一种更加直观的判据——HSI判据。
为什么说HSI判据是更加直观的判据呢?老规矩,先介绍一下HSI色彩模型:
HSI颜色模型用H、S、I三参数描述颜色特性,其中:
H表示颜色的色调,它表示人的感官对不同颜色的感受,如红色、绿色、蓝色等,它也可表示一定范围的颜色,如暖色、冷色等。
H的单位是°,代表与红轴的角度。
S表示颜色的饱和度,纯光谱色是完全饱和的,加入白光会稀释饱和度。饱和度越大,颜色看起来就会越鲜艳。
I对应成像亮度和图像灰度。
HSI模型的建立基于两个重要的事实: ① I分量与图像的彩色信息无关;② H和S分量与人感受颜色的方式是紧密相联的。
这些特点使得HSI模型非常适合彩色特性检测与分析。
对比一下RGB和HSI模型:
得出由RGB模型转化为HSI模型的公式:
假设R、G、B分量已经归一化到[0,1],那么求出来的S分量和I分量的值也会被归一化到[0,1]。当S分量为0的时候,对应的H分量也应该为0。
用OpenCV1.0可以根据上面的公式和条件写出模型转化函数的代码:
int cvBGR2HSI(IplImage*img_bgr, IplImage*img_hsi){
if (img_bgr == NULL || img_hsi == NULL){
printf("func cvBGR2HSI Error:\n");
printf("img_bgr == NULL || img_hsi == NULL\n");
return -1;
}
if (img_bgr->nChannels != 3 || img_hsi->nChannels != 3){
printf("func cvBGR2HSI Error:\n");
printf("img_bgr->nChannels != 3 || img_hsi->nChannels != 3\n");
return -1;
}
double eps = 1.111e-016;
double pi = 3.1416;
double num = 0;
double den = 0;
double theta = 0;
double R, G, B, H, S, I;
for (int i = 0; i < img_bgr->height; i++){
uchar*ptr1 = (uchar*)(img_bgr->imageData + i*img_bgr->widthStep);
uchar*ptr2 = (uchar*)(img_hsi->imageData + i*img_hsi->widthStep);
for (int j = 0; j < img_bgr->width; j++){
R = double(ptr1[3 * j + 2]) / 255.0;
G = double(ptr1[3 * j + 1]) / 255.0;
B = double(ptr1[3 * j + 0]) / 255.0;
num = 0.5*((R - G) + (R - B));
den = sqrt((R - G)*(R - G) + (R - B)*(G - B));
theta = acos(num / (den + eps));
H = theta;
if (B>G){
H = 2 * pi - H;
}
H = H / (2 * pi);
num = min(min(R, G), B);
den = R + G + B;
if (den < eps){
den = eps;
}
S = 1 - 3 * num / den;
if (S < eps){
H = 0;
}
I = (R + G + B) / 3.0;
ptr2[3 * j + 0] = H * 360;
ptr2[3 * j + 1] = S * 255;
ptr2[3 * j + 2] = I * 255;
}
}
return 0;
}
在代码中要注意的是在OpenCV中RGB三通道的排列顺序:先存放B分量,再存放G分量,最后才是R分量,这与MATLAB里面的规则是不同的。
有了模型转化函数之后,我们就可以在HSI色彩模型内使用HSI判据了。HSI判据很简单,也很直观,它的规则是每个分量设定两个阈值,满足
阈值条件的置1,不满足的置0。具体表达式如下:
H_min < H < H_max AND
S_min < S < S_max AND
I_min < I < I_max
在OpenCV1.0中可以轻松写出上面的代码:
int cvHSI_CHK(IplImage*img_hsi, IplImage*hsi_chk, int H_min, int H_max, int S_min, int S_max, int I_min, int I_max)
{
if (img_hsi == NULL || hsi_chk == NULL){
printf("func cvHSI_CHK Error:\n");
printf("img_hsi == NULL || hsi_chk == NULL)\n");
return -1;
}
if (img_hsi->nChannels != 3 || hsi_chk->nChannels != 1){
printf("func cvHSI_CHK Error:\n");
printf("img_hsi->nChannels != 3 || hsi_chk->nChannels != 1)\n");
return -1;
}
CvSize size = cvGetSize(img_hsi);
IplImage*H = cvCreateImage(size, 8, 1);
IplImage*S = cvCreateImage(size, 8, 1);
IplImage*I = cvCreateImage(size, 8, 1);
IplImage*mask = cvCreateImage(size, 8, 1);
cvSplit(img_hsi, H, S, I, NULL);
cvCmpS(H, H_min, mask, CV_CMP_GE);
cvCmpS(H, H_max, H, CV_CMP_LE);
cvMul(H, mask, H);
cvCmpS(S, S_min, mask, CV_CMP_GE);
cvCmpS(S, S_max, S, CV_CMP_LE);
cvMul(S, mask, S);
cvCmpS(I, I_min, mask, CV_CMP_GE);
cvCmpS(I, I_max, I, CV_CMP_LE);
cvMul(I, mask, I);
cvMul(H, S, H);
cvMul(H, I, hsi_chk);
cvConvertScale(hsi_chk, hsi_chk, 1.0 / 255);
cvReleaseImage(&H);
cvReleaseImage(&S);
cvReleaseImage(&I);
cvReleaseImage(&mask);
return 0;
}
根据实验经验,博主给出一组参考阈值:
H_min = 0 H_max = 60
S_min = 20 S_max = 100
I_min = 100 I_max = 255
参考上面给出的色相环可以轻松设定H分量的两个阈值,如果是想要检测其他颜色的火焰,可以根据需要做修改。
S分量的阈值较小,这与火焰所处的环境有关,若是在露天较明亮的地方检验,则需要调低一点;若在室内较暗的地方检验,则需要调高一点。
I分量的阈值较大,依据这么一个先验知识:火焰是会发光的。
最后,我们代入参考阈值检验一下图片看看效果如何:
我们可以看出,火焰的基本轮廓都提取出来了。若大家想要把整个区域都提取出来,可以自行尝试其它阈值。
基于OpenCV的火焰检测(三)——HSI颜色判据的更多相关文章
- 基于OpenCV的火焰检测(二)——RGB颜色判据
上文跟大家分享了在做火焰检测中常用到的图像预处理方法,从这一篇博文开始,我将向大家介绍如何一步一步地检测出火焰区域.火焰提取要用 到很多判据,今天我要向大家介绍的是最简单的但是很有效的判据--RGB判 ...
- 基于OpenCV的火焰检测(一)——图像预处理
博主最近在做一个基于OpenCV的火焰检测的项目,不仅可以检测图片中的火焰,还可以检测视频中的火焰,最后在视频检测的基础上推广到摄像头实时检测.在做这个项目的时候,博主参考了很多相关的文献,用了很多种 ...
- 基于OpenCv的人脸检测、识别系统学习制作笔记之一
基于OpenCv从视频文件到摄像头的人脸检测 在OpenCv中读取视频文件和读取摄像头的的视频流然后在放在一个窗口中显示结果其实是类似的一个实现过程. 先创建一个指向CvCapture结构的指针 Cv ...
- 【AdaBoost算法】基于OpenCV实现人脸检测Demo
一.关于检测算法 分类器训练: 通过正样本与负样本训练可得到分类器,opencv有编译好的训练Demo,按要求训练即可生成,这里我们直接使用其已经训练好的分类器检测: 检测过程: 检测过程很简单,可以 ...
- 基于Opencv的人脸检测及识别
一.实验目的:我这里完成的是,将8张人脸图片(4组,每组两张)存入库中,选取1张图片,程序识别出与其匹配的另一张. 这里介绍分三个步骤完成该工作,①程序读取摄像头.拍照 ②程序从电脑文档中读取图片 ...
- 基于OpenCv的人脸检测、识别系统学习制作笔记之三
1.在windows下编写人脸检测.识别系统.目前已完成:可利用摄像头提取图像,并将人脸检测出来,未进行识别. 2.在linux下进行编译在windows环境下已经能运行的代码. 为此进行了linux ...
- 基于OpenCv的人脸检测、识别系统学习制作笔记之二
在网上找到了一个博客,里面有大量内容适合初学者接触和了解人脸检测的博文,正好符合我目前的学习方面,故将链接放上来,后续将分类原博客的博文并加上学习笔记. 传送门: http://blog.sina.c ...
- 基于opencv的人脸检测的web应用
参考资料 https://github.com/bsdnoobz/web-based-face-detect http://opencv-code.com/projects/web-based-int ...
- OpenCV学习系列(一) Mac下OpenCV + xcode人脸检测实现
# OpenCV学习系列(一) Mac下OpenCV + xcode人脸检测实现 [-= 博客目录 =-] 1-学习目标 1.1-本章介绍 1.2-实践内容 1.3-相关说明 2-学习过程 2.1-环 ...
随机推荐
- Mybatis-config.xml配置文件详解
1.官方给出的案列: 注意:这些配置在文件中的顺序非常重要!必须严格按照上图中出现的顺序定义 2.properties属性 该属性主要作用就是引入外部的properties是文件,文件格式为xxx=x ...
- Java基础(7)-集合类3
list集合的特点 1)有序(存储和取出的元素一直) 2)可重复 List子类的特点 ArrayList 有序,可重复 底层数据结构是数组 查询快,增删慢 线程不安全,效率高 Vector 有序,可重 ...
- Codeforces Round #425 (Div. 2) D 树链剖分 + 树状数组维护区间
一看就知道 可以LCA判断做 也可以树链剖分拿头暴力 然而快速读入和线段树维护区间会T70 于是只能LCA? 线段树的常数不小 于是需要另外一种办法来进行区间加减和查询区间和 就是使用树状数组 这个题 ...
- QT QMimeData类
http://blog.csdn.net/xie376450483/article/details/5863810 QMimeData类提为数据提供一个容器,用来记录关于MIME类型数据的信息 QMi ...
- QT 利用QSplitter 分割区域, 并添加QScrollArea 滚动区域,滚动条
1. QSplitter 分割区域, 可以分割区域中可以随意添加自己的布局 2. #include "dialog.h" #include <QApplication> ...
- Spring初学之bean的生命周期
实体Bean: Car.java: package spring.beans.cycle; public class Car { private String name; private int pr ...
- openstack-ansible -- 3 Target hosts
Installing the operating system Install the Ubuntu Server 14.04 (Trusty Tahr) LTS 64-bit operating s ...
- Mssql 跨域查询
有数据库test1和数据库test2.其中test1中有表 table1.table2:test2 中有表 table1.三个表的字段都为为:id.xingming.shijian.shuliang. ...
- 一道问题引出的python中可变数据类型与不可变数据类型
一. 问题的提出 我们先来看两个对比 第一道题,当对象为整数时,最终结果:b = 2, a = 1,b的变化没有引起a的变化 a = 1 b = a b += 1 print(a) print(b) ...
- 20180831_jar包冲突2_天安微信httpclient冲突
一.异常现象 微信项目需要向腾讯服务器发送请求获取token. 但是在请求的时候抛了个异常: <2018-8-30 下午05时39分18秒 CST> <Notice> < ...