本文参考:https://blog.csdn.net/PecoHe/article/details/89927842
https://blog.csdn.net/weixin_41695564/article/details/80056430
-
前言
积分图算法由Crow在1984年首次提出,是为了在多尺度透视投影中提高渲染速度。积分图算法是一种快速计算图像区域和以及图像区域平方和的算法。它的核心思想就是对每一个图像建立起自己的积分图查找表,在图像处理的阶段就可以根据预先建立积分图查找表直接查找从而实现对均值卷积的线性时间计算。做到了卷积执行的时间与窗口大小无关。这种算法被应用到基于NCC的快速匹配、对象检测和SURF变换、边缘检测、基于统计学的快速滤波器等方面。
积分图算法的缺点:1、需要较大的内存来存储积分图。2、如果图片较大,会导致数据溢出。
-
积分图的建立
积分图由原图像计算而来,假设原图大小为W*H,则积分图大小为(W+1)*(H+1)。在积分图(integral image)上任意坐标(x,y)处的值,表示原图中坐标为(x,y)的点的左上角所有像素点像素值的和(平方和表中的就是平方和)。和表和平方和表建立公式如下:
和表:
平方和表:
如下图所示,假设输入图像大小为2x2,则积分图大小为3x3
-
积分图的查找
如上图所示,如果想求输入图像中蓝色区域内的像素值之和(3+2+5+4=14),只要根据和表积分图进行两次减法和一次减法即可:46+10-22-20=14。也就是右下角+左上角-右上角-左下角。
-
Opencv实例
opencv中计算积分图的API介绍:
//API一
void integral( InputArray src, //输入图像
OutputArray sum, //和表
int sdepth = -1,); //和表深度
//API二
void integral( InputArray src, //输入图像
OutputArray sum, //和表
OutputArray sqsum, //平方和表
int sdepth = -1, //和表深度,一般为CV_32S
int sqdepth = -1 ); //平方和表深度,一般为CV_32F
计算积分图并显示:
//
//opencv4.1.0
//
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main() {
Mat src, sum, sqrsum;
src = imread("1.png", 0);
integral(src, sum, sqrsum, CV_32S, CV_32F);
normalize(sum, sum, 0, 255, NORM_MINMAX, CV_8UC1, Mat());
normalize(sqrsum, sqrsum, 0, 255, NORM_MINMAX, CV_8UC1, Mat());
imshow("原图", src);
imshow("和表积分图", sum);
imshow("平方和表积分图", sqrsum);
waitKey(0);
return 0;
}
-
获取指定区域内像素值之和
//
//opencv4.1.0
//
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int get_block_sum(Mat &sum, int x1, int y1, int x2, int y2);
int main() {
Mat src, sum, sqrsum;
src = imread("1.png", 0);
//获取ROI,便于观察(使用ImageWatch插件)
int LR = 4;
int LC = 4;
int width = 6;
int height = 6;
Mat roi = src(Rect(LR, LC, width, height)).clone();
//计算积分图
integral(src, sum, sqrsum, CV_32S, CV_32F);
//利用积分图计算ROI内的像素值总和
int value = get_block_sum(sum, LR, LC, LR + height, LC + width);
cout << value << endl;
imshow("原图", src);
waitKey(0);
return 0;
}
int get_block_sum(Mat &sum, int x1, int y1, int x2, int y2) {
int BottomRight = sum.at<int>(x2, y2);
int TopLeft = sum.at<int>(x1, y1);
int TopRight = sum.at<int>(x1, x2);
int BottomLeft = sum.at<int>(x2, y1);
int sum_value = (BottomRight + TopLeft - TopRight - BottomLeft);
return sum_value;
}