积分图时一种允许子区域快速求和的数据结构,这种求和在很多方面都很有用,值得一提的是haar小波的计算,它用于人脸识别和类似的算法。Opencv支持积分图的三种变体,分别是总和、平方求和以及倾斜求和。每种情况的结果图像在图像的每个方向上都加1之后,与原始图像的大小相同。

通过积分图,你可以对图像的任意直立或“倾斜”的矩形区域求和、平均以及标准差。即使目标区域大小不确定,也可以高效进行快速模糊、近似梯度、求均值以及标准差,即使对可变大小的窗口,也可以执行快速块相关。

如果要计算中间区域的像素和,我们可以这样计算398-9-10+1=380。使用四个量就可以对任意矩形区域计算并且将计算复杂度控制为O(1)。

cv::integral()标准求和积分

void integral( InputArray src, OutputArray sum, int sdepth = -1 );

第一个参数和第二个参数是输入图像和输出图像,如果输入图像的大小时W×H,输出图像的大小就是(W+1)×(H+1)。第三个参数sdepth指明求和图像(结果图像)需要的深度。sdepth可以是CV:S32, CV::F32或CV::F64.

cv::integral()平方求和积分

void integral( InputArray src, OutputArray sum, OutputArray sqsum, int sdepth = -1, int sqdepth = -1 );

sqsum参数告诉函数除了标准求和还要计算平方和。与之前一样,sdepth指明目标图像的深度。sdepth可以是CV:S32, CV::F32或CV::F64.

cv::integral()倾斜求和积分

void integral( InputArray src, OutputArray sum, OutputArray sqsum, OutputArray tilted, int sdepth = -1, int sqdepth = -1 );

附加参数titled作为一个附加的项由函数计算而来,其他参数全部相同。

积分图应用(1)——均值滤波

通过利用积分图实现任意窗口大小的均值滤波,代码实现如下:

#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int getBlockSum(Mat& sum, int row1,int col1,int row2, int col2) {
int br = sum.at<int>(col2 + 1, row2 + 1);
int tl = sum.at<int>(col1, row1);
int tr = sum.at<int>(col2 + 1, row1);
int bl = sum.at<int>(col1, row2 + 1);
return br + tl - tr - bl;
}
void blur_demo(Mat &src, Mat& dst, int ksize) {
int h = src.rows;
int w = src.cols;
int radius = ksize / 2;
Mat sum;
integral(src, sum, CV_32S);
int row1, col1, row2, col2;
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
row1 = i - radius < 0 ? 0 : i - radius;
col1 = j - radius < 0 ? 0 : j - radius;
row2 = i + radius < w ? i + radius : w - 1;
col2 = j + radius < h ? j + radius : h - 1;
dst.at<uchar>(j, i) = (uchar)(getBlockSum(sum, row1, col1, row2, col2)/ ksize/ ksize);
}
}
} int main() {
Mat src = imread("D:/Backup/桌面/1.bmp", 0);
clock_t start, end;
start = clock();
int ksize = 5;
cout << "ksize = " << ksize << endl;
// 均值滤波
Mat dst1;
blur(src, dst1,Size(ksize, ksize),Point(-1,-1), BORDER_CONSTANT);
end = clock();
cout << "blur花费"<< end - start << endl;
// 积分图
start = clock();
Mat dst2 = Mat::zeros(src.size(), CV_8UC1);
blur_demo(src, dst2, ksize);
end = clock();
cout << "积分图花费" << end - start << endl;
return 0;
}

积分图应用(2)——动态阈值分割dyn_threshold

原理: 动态阈值分割是指在图像分割的过程中,不用人为的去设置阈值,而是根据图像中存在的特征,进行分割。一般是将原图像与处理后的图像作差,然后去计算差值图像中的亮色区域或者暗色区域。其本质相当于对图像灰度直方图的平滑,进而求取图像中的波谷或者波峰。

pixel = (pixel > (mean - c)) ? object : background

其中默认情况下参数C取值为0。object表示前景像素,background表示背景像素。

特点: 动态阈值分割具有抗干扰性强,稳定性强的特点,对光照变化不敏感。

  • 使用均值滤波+二值化实现动态阈值
int ksize = 7;
Mat mean, sub, dst1;
blur(src, mean, Size(ksize, ksize));
subtract(mean, src, sub);
threshold(sub, dst1, 10, 255, THRESH_BINARY_INV);
  • 使用积分图实现动态阈值
/*实现步骤
1. 彩色图像转灰度图像
2. 获取灰度图像的像素数据,预计算积分图
3. 根据输入的参数窗口半径大小从积分图中获取像素总和,求得平均值
4. 循环每个像素,根据局部均值实现中心像素的二值化赋值
5. 输出二值图像*/
void dyn_threshold(Mat &src, Mat& dst, int ksize, int c) {
int h = src.rows;
int w = src.cols;
int radius = ksize / 2;
Mat sum;
integral(src, sum, CV_32S);
int row1, col1, row2, col2;
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
row1 = i - radius < 0 ? 0 : i - radius;
col1 = j - radius < 0 ? 0 : j - radius;
row2 = i + radius < w ? i + radius : w - 1;
col2 = j + radius < h ? j + radius : h - 1;
dst.at<uchar>(j, i) = src.at<uchar>(j, i) - (uchar)(getBlockSum(sum, row1, col1, row2, col2) / ksize / ksize) + c>0 ? 255 : 0;
}
}
}

结果:运行时间差不多

积分图应用(3)——var_threshold

var_threshold的分割,非常适用于具有较为复杂背景的标识内容进行分割,它能够对获取指定蒙板大小且具有相同灰度的目标进行分割。

算子的函数签名如下:

var_threshold(Image : Region : MaskWidth, MaskHeight, StdDevScale, AbsThreshold, LightDark : )

其中,MaskWidth、 MaskHeight 定义的过滤器蒙板大小决定了要分割的对象的最大尺寸,但是,如果选择的蒙版太大,则可能会合并非常接近的对象。

StdDevScale 局部标准差用作图像中噪声的度量,它可以通过StdDevScale进行缩放,以反映所需的灵敏度,值越高,表示仅选择与其周围环境截然不同的像素。

AbsThreshold则为目标区域的绝对灰度值,在图像的均匀区域中,标准偏差较低;因此,单个灰度值的影响很大,为了降低在均匀区域中的灵敏度,可以调整AbsThreshold。因此,可以忽略同质环境中的微小灰度值变化。

请注意,对于 StdDevScale 的负值,AbsThreshold 也应选择负值。

lightDark: dark 暗 light 光亮 equal 等于 not_equal 不等于

令g(x,y)为点(x,y)处的灰度值,m(x,y) 为均值,d(x,y) 为方差(实际是标准差),则点(x,y)处的阈值v(x,y)定义为:

当LightDark = ‘light’:时,满足下述条件的点被选中到输出区域

当LightDark = ‘dark’:时,满足下述条件的点被选中到输出区域

当LightDark = ‘equal’:时,满足下述条件的点被选中到输出区域

当LightDark = ‘not_equal’:时,满足下述条件的点被选中到输出区域

代码实现:

void var_threshold(Mat& src, Mat& dst, int StdDevScale, int AbsThreshold, int ksize) {
int h = src.rows;
int w = src.cols;
int radius = ksize / 2;
Mat mean, sub, sum, qsum;
blur(src, mean, Size(ksize, ksize));
subtract(mean, src, sub);
integral(sub, sum, qsum, CV_32S, CV_32S);
int row1, col1, row2, col2;
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
row1 = i - radius < 0 ? 0 : i - radius;
col1 = j - radius < 0 ? 0 : j - radius;
row2 = i + radius < w ? i + radius : w - 1;
col2 = j + radius < h ? j + radius : h - 1;
int varthreshold = max(StdDevScale * (int)sqrt(getBlockSum(qsum, row1, col1, row2, col2)) / ksize, AbsThreshold);
dst.at<uchar>(j, i) = src.at<uchar>(j, i) - mean.at<uchar>(j, i) - varthreshold>0?255:0;
}
}
}

参考文献:

1.图像处理之积分图应用四(基于局部均值的图像二值化算法)

2. OpenCV中积分图介绍与应用

Opencv笔记(13)积分图的更多相关文章

  1. 颜色空间转换 cvtColor()[OpenCV 笔记13]

    void cvtColor(InputArray src, OutputArray dst, ) src: 输入图像 dst: 输出图像 code: 颜色空间转换标识符 OpenCV2的CV_前缀宏命 ...

  2. OpenCv关于灰度积分图的SSE代码学习和改进。

    最近一直沉迷于SSE方面的优化,实在找不到想学习的参考资料了,就拿个笔记本放在腿上翻翻OpenCv的源代码,无意中看到了OpenCv中关于积分图的代码,仔细研习了一番,觉得OpenCv对SSE的灵活运 ...

  3. SSE图像算法优化系列六:OpenCv关于灰度积分图的SSE代码学习和改进。

    最近一直沉迷于SSE方面的优化,实在找不到想学习的参考资料了,就拿个笔记本放在腿上翻翻OpenCv的源代码,无意中看到了OpenCv中关于积分图的代码,仔细研习了一番,觉得OpenCv对SSE的灵活运 ...

  4. Opencv中integral计算积分图

    Paul Viola和Michael Jones在2001年首次将积分图应用在图像特征提取上,在他们的论文"Rapid Object Detection using a Boosted Ca ...

  5. OpenCV笔记大集锦(转载)

    整理了我所了解的有关OpenCV的学习笔记.原理分析.使用例程等相关的博文.排序不分先后,随机整理的.如果有好的资源,也欢迎介绍和分享. 1:OpenCV学习笔记 作者:CSDN数量:55篇博文网址: ...

  6. opencv笔记3:trackbar简单使用

    time:2015年 10月 03日 星期六 13:54:17 CST # opencv笔记3:trackbar简单使用 当需要测试某变量的一系列取值取值会产生什么结果时,适合用trackbar.看起 ...

  7. 机器学习实战 - 读书笔记(13) - 利用PCA来简化数据

    前言 最近在看Peter Harrington写的"机器学习实战",这是我的学习心得,这次是第13章 - 利用PCA来简化数据. 这里介绍,机器学习中的降维技术,可简化样品数据. ...

  8. opencv笔记6:角点检测

    time:2015年10月09日 星期五 23时11分58秒 # opencv笔记6:角点检测 update:从角点检测,学习图像的特征,这是后续图像跟踪.图像匹配的基础. 角点检测是什么鬼?前面一篇 ...

  9. opencv笔记5:频域和空域的一点理解

    time:2015年10月06日 星期二 12时14分51秒 # opencv笔记5:频域和空域的一点理解 空间域和频率域 傅立叶变换是f(t)乘以正弦项的展开,正弦项的频率由u(其实是miu)的值决 ...

  10. opencv笔记4:模板运算和常见滤波操作

    time:2015年10月04日 星期日 00时00分27秒 # opencv笔记4:模板运算和常见滤波操作 这一篇主要是学习模板运算,了解各种模板运算的运算过程和分类,理论方面主要参考<图像工 ...

随机推荐

  1. 【笔记】Oracle union all&for update锁

    [笔记]Oracle union all&for update union all 在Oracle中有三种类型的集合操作 UNION:求并,重复记录只显示一次 UNION ALL:求并集,显示 ...

  2. 存储过程编写·记(“xxx“在需要下列之一:if)

    存储过程编写·记("xxx"在需要下列之一:if) 使用的数据库为Oracle数据库,数据库客户端为DBeaver 简单来说,就是使用SQL语句进行一些函数编写,进而进行一些过滤啊 ...

  3. 力扣1768(java&python)-交替合并字符串(简单)

    题目: 给你两个字符串 word1 和 word2 .请你从 word1 开始,通过交替添加字母来合并字符串.如果一个字符串比另一个字符串长,就将多出来的字母追加到合并后字符串的末尾. 返回 合并后的 ...

  4. 5G新基建 边缘计算乘风破浪

    作者 | 张羽辰(同昭)阿里云交付专家 导读:如今,几乎所有的事情都离不开软件,当你开车时,脚踩上油门,实际上是车载计算机通过力度感应等计算输出功率,最终来控制油门,你从未想过这会是某个工程师的代码. ...

  5. 阿里巴巴在 Envoy Gateway 的演进历程浅析

    ​简介:最近阅读 <Envoy Gateway 来了>这篇文章,深感 Envoy 强大的可扩展性和基于 Envoy Gateway 带来的易用性,在 K8s 架构下,Envoy 重新定义了 ...

  6. T级内存,创建效率提升10倍以上,阿里云 KVM异构虚拟机启动时间优化实践

    简介: 阿里云工程师李伟男和郭成在 KVM Forum 2020 上详细介绍了阿里云 KVM 虚拟机创建及启动时间优化的具体技术实现,本文根据其演讲整理而成. 对于云计算用户来说,过长的 KVM 虚拟 ...

  7. Elasticsearch生态&技术峰会 | 阿里云Elasticsearch云原生内核

    简介: 开源最大的特征就是开放性,云生态则让开源技术更具开放性与创造性,Elastic 与阿里云的合作正是开源与云生态共生共荣的典范.值此合作三周年之际,我们邀请业界资深人士相聚云端,共话云上Elas ...

  8. PolarDB for PostgreSQL 开源路线图

    ​简介:作者:蔡乐 本文主要分享一下Polar DB for PG的开源路线图,虽然路线图已经拟定,但是作为开源产品,所有参与者都能提出修改意见,包括架构核心特性的技术以及周边生态和工具等,希望大家能 ...

  9. Servlet注解的使用,简化配置 以及,使用模板方法设计模式优化oa项目

    Servlet注解的使用,简化配置 以及,使用模板方法设计模式优化oa项目 每博一文案 有句谚语说:"一怒之下踢石头,只有痛着脚趾头." 比一件糟糕的事情更可拍的,是你用糟糕的态度 ...

  10. ide构建SpringMVC框架

    框架原理图如下: 1. 创建如图项目 2. 在lib中所需导入jar包 3. 配置变量 (1) (2)add library (3)选择web app libraries 4. 配置web.xml文件 ...