版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huanghuangjin/article/details/81669468
有了积分图像,在做卷积的时候就可以大大减少运算次数,从而提升速度。
还可以计算积分平方和表,用于一些特殊的矩阵变换。
积分图应用:
快速模糊
快速匹配
快速马赛克
代码
#include "../common/common.hpp"
static void mean_blur(Mat &image, Mat &sum, int size);
void main(int argc, char** argv)
{
Mat src = imread(getCVImagesPath("images/lena.png"));
imshow("src9-5", src);
Mat sum, sqrsum;
integral(src, sum, sqrsum, CV_32S, CV_32F); // 计算积分和表于积分平方和表,sum sqrsum 设置为什么深度,看具体情况
// [512 x 512],[513 x 513],[513 x 513] 计算出来的积分和表与积分平方和表的宽高比原图的宽高大1个尺寸,且第1行第1列的值都为0
cout << src.size() << "," << sum.size() << "," << sqrsum.size() << endl;
int size = 25; // 卷积的宽度
mean_blur(src, sum, size);
Mat dst;
double time = getTickCount();
blur(src, dst, Size(size, size), Point(-1, -1));
cout << "blur time=" << (getTickCount() - time) / getTickFrequency() << endl; // blur time=0.0363686
imshow("blur9-5", dst);
waitKey(0);
}
void mean_blur(Mat &image, Mat &sum, int size) // 利用积分图实现均值模糊,比opencv的blur函数计算速度慢了10倍,将下面算法改成指针版速度会快?
{
int w = image.cols; // 原图宽高
int h = image.rows;
Mat result = Mat::zeros(image.size(), image.type()); // 最终计算出来的均值图像
int x2 = 0, y2 = 0; // 这四个值用于在积分和表中标定要计算的积分区域的位置
int x1 = 0, y1 = 0;
int ksize = size; // 要计算的积分区域的宽度,即相当于卷积的宽度
int radius = ksize / 2; // 一半
int ch = image.channels(); // 原图通道数
int cx = 0, cy = 0; // 卷积的中心点坐标
double time = getTickCount();
for (int row = 0; row < h + radius; row++) // h + radius 这里只是为了后面计算卷积中心点cx,xy 并不是考虑了border
{
y2 = (row + 1) > h ? h : (row + 1); // row + 1 是因为和表比原图尺寸大1
y1 = (row - ksize) < 0 ? 0 : (row - ksize); // 当row还不够ksize大小的时候,要计算的积分区域的上边两个点的值为0
for (int col = 0; col < w + radius; col++) // w + radius 这里只是为了后面计算卷积中心点cx,xy 并不是考虑了border
{
x2 = (col + 1) > w ? w : (col + 1); // col + 1 是因为和表比原图尺寸大1
x1 = (col - ksize) < 0 ? 0 : (col - ksize); // 当col还不够ksize大小的时候,要计算的积分区域的左边两个点的值为0
for (int i = 0; i < ch; i++) // 计算各通道上的均值
{
int tl = sum.at<Vec3i>(y1, x1)[i]; // 上左的i通道
int tr = sum.at<Vec3i>(y1, x2)[i]; // 上右的i通道
int bl = sum.at<Vec3i>(y2, x1)[i]; // 下左的i通道
int br = sum.at<Vec3i>(y2, x2)[i]; // 下右的i通道
int s = br - bl - tr + tl; // 区域积分和计算公式
cx = (col - radius) < 0 ? 0 : col - radius; // 获取'卷积'的中心点,当row,col小于radius的时候,这里都是取的目标图像的0,0位置
cy = (row - radius) < 0 ? 0 : row - radius; // 这里的算法并没有考虑border
int num = (x2 - x1)*(y2 - y1); // 积分区域的真实像素点的数目
result.at<Vec3b>(cy, cx)[i] = saturate_cast<uchar>(s / num); // 积分区域的均值赋给目标图像cx,cy像素点的i通道,saturate_cast 值范围锁定在 0-255
}
}
}
cout << "mean_blur time=" << (getTickCount() - time) / getTickFrequency() << endl; // mean_blur time=0.363893
imshow("blured-image", result);
}