图像平滑之积分图加速 c++ opencv实现

积分图

原理

快速计算图像区域和以及图像区域平方和
在这里插入图片描述在这里插入图片描述
上述原理用公式表示为:
I ( x , y ) = I ( x − 1 , y ) + I ( x , y − 1 ) − I ( x − 1 , y − 1 ) + p i x e l ( x , y ) I(x,y) = I(x-1,y) + I(x,y-1) - I(x-1,y-1) + pixel(x,y) I(x,y)=I(x1,y)+I(x,y1)I(x1,y1)+pixel(x,y)
此外还需要考虑边界问题,也就是第一行和第一列的计算。
对于第一行:
I ( 0 , 0 ) = p i x e l ( 0 , 0 ) , x = 0 , y = 0 I ( x , 0 ) = I ( x − 1 , 0 ) + p i x e l ( x , 0 ) , x > 0 , y = 0 I(0,0) = pixel(0,0),x=0,y=0 I(x,0) = I(x-1,0) + pixel(x,0),x>0,y=0 I(0,0)=pixel(0,0)x=0y=0I(x,0)=I(x1,0)+pixel(x,0)x>0y=0
对于第一列:
I ( 0 , y ) = I ( 0 , y − 1 ) + p i x e l ( 0 , y ) , x = 0 , y > 0 I(0,y) = I(0,y-1) + pixel(0,y),x=0,y>0 I(0,y)=I(0,y1)+pixel(0,y)x=0y>0

代码实现

积分图

//实现积分图
cv::Mat myIntegral(  cv::Mat & src)
{
 
	cv::Mat dst;
	dst = cv::Mat::zeros(src.size(), src.type());//创建一个空矩阵
	for (int y = 0; y < src.rows; ++y) {
		for (int x = 0; x < src.cols; ++x) {
			for (int c = 0; c < 3; ++c) {
				int sum = src.at<cv::Vec3b>(y, x)[c];

				if (y > 0) {
					sum += dst.at<cv::Vec3b>(y - 1, x)[c];
				}

				if (x > 0) {
					sum += dst.at<cv::Vec3b>(y, x - 1)[c];
				}

				if (y > 0 && x > 0) {
					sum -= dst.at<cv::Vec3b>(y - 1, x - 1)[c];
				}

				dst.at<cv::Vec3b>(y, x)[c] = sum;
			}
		}
	}
	return dst;
}

积分图均值平滑

cv::Mat smoothBymyIntegral( cv::Mat& src, int windowSize) {
	CV_Assert(src.type() == CV_8UC3 && windowSize % 2 == 1);

	cv::Mat integralImg;
	cv::integral(src, integralImg, CV_32S);

	cv::Mat dst = src.clone();
	int halfWindowSize = windowSize / 2;

	for (int y = 0; y < src.rows; ++y) {
		for (int x = 0; x < src.cols; ++x) {
			int x1 = std::max(x - halfWindowSize, 0);
			int y1 = std::max(y - halfWindowSize, 0);
			int x2 = std::min(x + halfWindowSize + 1, src.cols);
			int y2 = std::min(y + halfWindowSize + 1, src.rows);

			for (int c = 0; c < 3; ++c) {
				int sum = integralImg.at<cv::Vec3i>(y2, x2)[c] - integralImg.at<cv::Vec3i>(y1, x2)[c] - integralImg.at<cv::Vec3i>(y2, x1)[c] + integralImg.at<cv::Vec3i>(y1, x1)[c];
				int area = (x2 - x1) * (y2 - y1);
				dst.at<cv::Vec3b>(y, x)[c] = static_cast<uchar>(sum / area);
			}
		}
	}

	return dst;
}

均值平滑

//均值平滑函数
Mat smoothImage(const Mat& inputImage, int Sx, int Sy)
{
	Mat smoothed;
	inputImage.copyTo(smoothed);

	int channels = smoothed.channels();
	int width = smoothed.cols;
	int height = smoothed.rows;

	// 遍历图像像素
	for (int i = Sy; i < height - Sy; i++)
	{
		for (int j = Sx; j < width - Sx; j++)
		{
			// 计算窗口内像素的平均灰度
			double sum0 = 0;
			double sum1 = 0;
			double sum2 = 0;
			for (int m = -Sy; m <= Sy; m++)
			{
				for (int n = -Sx; n <= Sx; n++)
				{
					if (channels == 1)
						sum1 += smoothed.at<uchar>(i + m, j + n);
					else if (channels == 3)
					sum0 += smoothed.at<Vec3b>(i + m, j + n)[0]; 
					sum1 += smoothed.at<Vec3b>(i + m, j + n)[1];
					sum2 += smoothed.at<Vec3b>(i + m, j + n)[2];
				}
			}

			// 将平均灰度赋给中心像素
			if (channels == 1)
				smoothed.at<uchar>(i, j) = static_cast<uchar>(sum1 / ((2 * Sx + 1) * (2 * Sy + 1)));
			else if (channels == 3)
			{
				Vec3b& pixel = smoothed.at<Vec3b>(i, j);
				pixel[0] = static_cast<uchar>(sum0/ ((2 * Sx + 1) * (2 * Sy + 1))); 
                pixel[1] = static_cast<uchar>(sum1 / ((2 * Sx + 1) * (2 * Sy + 1)));
			    pixel[2] = static_cast<uchar>(sum2 / ((2 * Sx + 1) * (2 * Sy + 1))); 
			}
		}
	}

	return smoothed;
}

实验结果

原图
在这里插入图片描述

积分图均值平滑

5*5模板

积分图

在这里插入图片描述

积分图平滑函数

在这里插入图片描述

均值平滑

opencv自带平滑函数

在这里插入图片描述

自己实现平滑函数

在这里插入图片描述

运行时间比较

方法运行时间 单位:s
5*511*11
opencv自带0.00032090.0002521
自己实现均值滤波器0.00241350.0098366
积分图加速均值滤波器0.00151640.001455

结论:积分图实现加快滤波器执行速度

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值