基于HEP(histograms of equivalent patterns【1】)框架下的特征具有良好的纹理分类效果,LBP(local binary patterns【2】)属于HEP框架下最常用的特征,具有对亮度、旋转等良好的不变特性。在基于分块的视频烟雾检测中,常使用其作为纹理分类的特征。然而,分块的图像具有局部性。这篇文章主要提出使用图像金字塔的方法让提取的烟雾块特征具有一定的全局属性。它将待检测烟雾块构成3级的金字塔,再对金字塔每一级提取不同模式的LBP特征,构成一个直方图序列作为特征向量,最后采用神经网络分类。

1.LBP 与 LBPV

本文用到的LBP共三种模式:统一模式,旋转不变模式,统一的旋转不变模式。每一级金字塔采用一种模式。LBP详见博客【3】

LBPV与LBP不同的是,LBP统计直方图的时候是每一个LBP(i,j)使第k个分量加1,而LBPV是加一个VAR(方差吧),VAR计算公式:

上面gp为领域内像素值,然后再归一化。

2.金字塔

共三级金字塔,I0,I1,I2,I0为输入图像,I0通过高斯低通滤波(Gaussian low pass filter, LPF),然后下采样得到I1(采样大小2),同样由I1得到I2,如图:

最后从下到上对每一级分别提取统一模式LBP,旋转不变LBP,统一旋转不变LBP,按照如下的顺序组合成向量:

对于24x24的图像块,I2的大小仅为6x6,这样会获得稀疏的特征向量,不利于分类。因此,I1和I2通过相邻像素增大搜索窗口。如图:

3.实现

本人采用文章中的数据集作为训练与测试,剪切成96x96的灰度图,这样大小的图像下采样两次刚好24x24。提取每一张图像特征代码:

feature_t get_pyramid_feature(cv::Mat & img)
{
assert((img.dims == 2) && (img.rows == 96) && (img.cols == 96));
feature_t result, lbp0, lbp1, lbp2, lbpv0, lbpv1, lbpv2;
result.resize(210);
cv::Mat I0, I1, I2, L0, S0, L1; I0 = img(cv::Rect(36, 36, 24, 24)).clone();
cv::GaussianBlur(img, L0, cv::Size(3,3), 0);
cv::resize(L0, S0, cv::Size(48, 48));
I1 = S0(cv::Rect(12, 12, 24, 24)).clone();
cv::GaussianBlur(S0, L1, cv::Size(3,3), 0);
cv::resize(L1, I2, cv::Size(24, 24)); lbp0 = get_u_lbp_gray(I0);
lbp1 = get_ri_lbp_gray(I1);
lbp2 = get_riu_lbp_gray(I2);
lbpv0 = get_u_lbpv_gray(I0);
lbpv1 = get_ri_lbpv_gray(I1);
lbpv2 = get_riu_lbpv_gray(I2); std::copy(lbp0.begin(), lbp0.end(), result.begin());
std::copy(lbpv0.begin(), lbpv0.end(), result.begin()+59);
std::copy(lbp1.begin(), lbp1.end(), result.begin()+118);
std::copy(lbpv1.begin(), lbpv1.end(), result.begin()+154);
std::copy(lbp2.begin(), lbp2.end(), result.begin()+190);
std::copy(lbpv2.begin(), lbpv2.end(), result.begin()+200);
return result;
}

提取特征过后,采用神经网络训练(采样tiny_cnn这个轻量级的神经网络库):

void mlp_train(std::vector<feature_t> & train_x, std::vector<int> & train_y, std::vector<feature_t> & test_x, std::vector<int> & test_y, const char * weights_file, int iter_num = 20)
{
const int num_input = train_x[0].size();
const int num_hidden_units = 30;
int num_units[] = { num_input, num_hidden_units, 2 };
auto nn = make_mlp<mse, gradient_descent_levenberg_marquardt, tan_h>(num_units, num_units + 3); //train mlp
nn.optimizer().alpha = 0.005;
boost::progress_display disp(train_x.size());
boost::timer t;
// create callback
auto on_enumerate_epoch = [&](){
std::cout << t.elapsed() << "s elapsed." << std::endl;
tiny_cnn::result res = nn.test(test_x, test_y);
std::cout << nn.optimizer().alpha << "," << res.num_success << "/" << res.num_total << std::endl;
nn.optimizer().alpha *= 0.85; // decay learning rate
nn.optimizer().alpha = std::max(0.00001, nn.optimizer().alpha);
disp.restart(train_x.size());
t.restart();
};
auto on_enumerate_data = [&](){
++disp;
}; nn.train(train_x, train_y, 1, iter_num, on_enumerate_data, on_enumerate_epoch);
nn.test(test_x, test_y).print_detail(std::cout);
nn.save_weights(weights_file);
}

最后得到测试的结果96%以上。

然后用于视频的处理中,只用处理单幅图像的情况。对于一副图像,首先得分块,将每一个分块的区域保存到向量中。分块的时候就考虑到金字塔每一级,因此3级的每一个向量对应的位置是对应的一个块。对于边缘块的处理忽略图像外的像素。分块代码如下:

std::vector<std::vector<cv::Rect>> make_image_blocks(const cv::Mat &in, const int iWD)
{
std::vector<std::vector<cv::Rect>> result;
std::vector<cv::Rect> level0, level1, level2;
int rows = in.rows;
int cols = in.cols;
int rows_level1 = rows / 2;
int cols_level1 = cols / 2;
int rows_level2 = rows / 4;
int cols_level2 = cols / 4;
int left, top, right, bottom;
for(int i = 0; i <= rows - iWD; i += iWD)
{
for(int j = 0; j <= cols - iWD; j += iWD)
{
level0.push_back(cv::Rect(j, i, iWD, iWD));
//level1
left = std::max(j/2-6,0);
top = std::max(i/2-6,0);
right = std::min(j/2+18, cols_level1);
bottom = std::min(i/2+18, rows_level1);
level1.push_back(cv::Rect(left, top, right-left, bottom-top));
//level2
left = std::max(j/4-9,0);
top = std::max(i/4-9,0);
right = std::min(j/4+15, cols_level2);
bottom = std::min(i/4+15, rows_level2);
level2.push_back(cv::Rect(left, top, right-left, bottom-top));
}
}
result.push_back(level0);
result.push_back(level1);
result.push_back(level2);
return result;
}

然后就是对每一张图像的处理了,首先创建3级金字塔,然后按照上面得到的分块索引轻松得到每一块的特征,然后predict就完事了。

template<typename NN>
std::vector<int> single_image_smoke_detect(const cv::Mat & img, const std::vector<std::vector<cv::Rect>> & locate_list, const std::vector<int> smoke_block, NN & nn)
{
std::vector<int> result;
cv::Mat I1, I2, L0, L1;
cv::GaussianBlur(img, L0, cv::Size(3,3), 0);
cv::resize(L0, I1, cv::Size(img.cols/2, img.rows/2));
cv::GaussianBlur(I1, L1, cv::Size(3,3), 0);
cv::resize(L1, I2, cv::Size(I1.cols/2, I1.rows/2)); for(auto i : smoke_block)
{
cv::Mat block = img(locate_list[0][i]);
auto lbp0 = get_u_lbp_gray(block);
auto lbpv0 = get_u_lbpv_gray(block);
block = I1(locate_list[1][i]);
auto lbp1 = get_ri_lbp_gray(block);
auto lbpv1 = get_ri_lbpv_gray(block);
block = I2(locate_list[2][i]);
auto lbp2 = get_riu_lbp_gray(block);
auto lbpv2 = get_riu_lbpv_gray(block); feature_t feat;
feat.resize(210,0);
std::copy(lbp0.begin(), lbp0.end(), feat.begin());
std::copy(lbpv0.begin(), lbpv0.end(), feat.begin()+59);
std::copy(lbp1.begin(), lbp1.end(), feat.begin()+118);
std::copy(lbpv1.begin(), lbpv1.end(), feat.begin()+154);
std::copy(lbp2.begin(), lbp2.end(), feat.begin()+190);
std::copy(lbpv2.begin(), lbpv2.end(), feat.begin()+200); vec_t y;
nn.predict(feat, &y);
const int predicted = max_index(y);
if(predicted == 1)
result.push_back(i);
}
return result;
}

在这之前加入运动检测:

smoke_blocks = single_image_smoke_detect(gray_img, locate_list, smoke_blocks, nn);

然后将检测得到的烟雾块显示出来:

auto merged_blocks = merge_blocks(smoke_blocks, gray_img.size(), 24);
for(auto rect : merged_blocks)
{
cv::rectangle(img, rect, cv::Scalar(0,0,255));
} cv::imshow("smoke", img);

效果图:

1.实验结果分析

试了一下仅使用LBP或LBPV的情况下,单独使用LBPV的分类效果最差,多次测试平均94%多一点,而LBP和LBP+LBPV情况差不多,平均都在96%以上,因此,不加LBPV更好一点。

2.总结

加入金字塔对每一级提取特征的方法的确比单独采用分块提取特征的方法稍好一点,但是对于烟雾的检测,单帧的检测并不能满足于实际。这个可以作为一个novel方法用在一个框架中。

6.引用

【1】 Texture description through histograms of equivalent patterns

【2】  Multiresolution gray-scale and rotation invariant texture classification with local binary patterns

【3】  http://blog.csdn.net/zouxy09/article/details/7929531

@waring

烟雾检测笔记1--《Video-based smoke detection with histogram sequence of LBP and LBPV pyramids》解析、实现的更多相关文章

  1. paper 27 :图像/视觉显著性检测技术发展情况梳理(Saliency Detection、Visual Attention)

    1. 早期C. Koch与S. Ullman的研究工作. 他们提出了非常有影响力的生物启发模型. C. Koch and S. Ullman . Shifts in selective visual ...

  2. 个性探测综述阅读笔记——Recent trends in deep learning based personality detection

    目录 abstract 1. introduction 1.1 个性衡量方法 1.2 应用前景 1.3 伦理道德 2. Related works 3. Baseline methods 3.1 文本 ...

  3. 论文阅读笔记五十二:CornerNet-Lite: Efficient Keypoint Based Object Detection(CVPR2019)

    论文原址:https://arxiv.org/pdf/1904.08900.pdf github:https://github.com/princeton-vl/CornerNet-Lite 摘要 基 ...

  4. Tensorflow Object_Detection 目标检测 笔记

    Tensorflow models Code:https://github.com/tensorflow/models 编写时间:2017.7 记录在使用Object_Detection 中遇到的问题 ...

  5. 论文笔记: Deep Learning based Recommender System: A Survey and New Perspectives

    (聊两句,突然记起来以前一个学长说的看论文要能够把论文的亮点挖掘出来,合理的进行概括23333) 传统的推荐系统方法获取的user-item关系并不能获取其中非线性以及非平凡的信息,获取非线性以及非平 ...

  6. 谣言检测(ClaHi-GAT)《Rumor Detection on Twitter with Claim-Guided Hierarchical Graph Attention Networks》

    论文信息 论文标题:Rumor Detection on Twitter with Claim-Guided Hierarchical Graph Attention Networks论文作者:Erx ...

  7. 论文笔记--PCN:Real-Time Rotation-Invariant Face Detection with Progressive Calibration Networks

    关键词:rotation-invariant face detection, rotation-in-plane, coarse-to-fine 核心概括:该篇文章为中科院计算所智能信息处理重点实验室 ...

  8. 谣言检测(GACL)《Rumor Detection on Social Media with Graph Adversarial Contrastive Learning》

    论文信息 论文标题:Rumor Detection on Social Media with Graph AdversarialContrastive Learning论文作者:Tiening Sun ...

  9. 谣言检测(RDEA)《Rumor Detection on Social Media with Event Augmentations》

    论文信息 论文标题:Rumor Detection on Social Media with Event Augmentations论文作者:Zhenyu He, Ce Li, Fan Zhou, Y ...

随机推荐

  1. Entify Framewrok - Join的使用方法

    问题:有2个表,使用id相连,如何用Join语法将其连接起来? 如下代码 List<tblAssociation> assoList = dataContext.tblAssociatio ...

  2. poj 2049 Let it Bead(polya模板)

      Description Cannery Row percent of the target audience insists that the bracelets be unique. (Just ...

  3. 使用openCV的静态库编译

    转载请注明出处: http://www.cnblogs.com/sysuzyq/p/6183568.html By 少侠阿朱 摘要: 本文主要讲述如何使用opencv静态库进行编译,生成脱离openc ...

  4. <Win32_6>程序员求爱的创意程序^_^

    作为程序员,我们时常被外界误认为很闷.不浪漫.没创意……等等这一类人,这让我们实在有些感伤啊,我得为程序员呐喊一声: 我们也能可以欢快.浪漫.有创意…… 朋友,你向女生表白过吗? …… 这个问题有点儿 ...

  5. 《31天成为IT服务达人》之技能篇硬件维护技能概要

     server维护技能 server硬件作为应用软件部署的基础平台,是基础架构中最为核心的设备.一旦server出现问题就会影响业务的正常开展.因此,server的运维管理对于企业整个IT运维管理 ...

  6. LVM管理

    一.步骤: 1.创建新的分区,并修改分区类型为8e 2.创建物理卷PV 3.将新建的PV添加到要扩展的VG中 4.用命令lvextend或lvresize来将新加入的PE添加到要扩展的LV中 5.用命 ...

  7. java基础之代理

    代理的定义,代理的应用,代理的特性

  8. Visual Studio 命中断点时 打印信息

    打印时间: 开始: {DateTime.Now.ToString()} 结束: {DateTime.Now.ToString()} 搜索 复制

  9. asp net 编程问题 实现下一篇 和上一篇效果

    首先是access数据库,有一个名为news的表,里面有三个字段,分别为id,classid 和name 其中id为主键,classid可以重复 现在有以下数据: id classid name 1 ...

  10. 图文混排——用表情代替"[文字]"

    1.简单设置带属性的字符串 定义一个NSMutableAttributedString带属性的字符串 NSMutableAttributedString *str = [[NSMutableAttri ...