视线逐渐模糊 (二维前缀和) ZJUT1003

视线逐渐模糊

描述

均值模糊算法的具体流程如下:
给定一张图片,使用一个卷积核在图像上进行卷积操作,得到一张新的图片。其中卷积核为长宽均为rr的正方形,且rr通常为奇数。例如当r=5时,卷积核为5×5,每个元素都为1/25的正方形。
卷积的操作是将卷积核的中心放于一个像素上,并与图像对应的部分相乘累加,得到新的像素。当处理图像边缘时,选择扩展边界的方法。
以测试输入为例,当卷积核为3时,先扩展图像,如下所示:

2 2 5 4 4

2 2 5 4 4

6 6 7 5 5

4 4 3 2 2

4 4 3 2 2

当卷积核置于左上角时,得到的累加结果为37/9,向下取整为4。此后卷积核右移,得到的结果为40/9,向下取整为4。类似的操作会执行9次,得到最终的图像。
是不是还挺简单的,但是Martin实在是太笨了。现在Martin找了几张图片,希望你帮他用均值模糊算法处理一下下。

输入

多组测试数据,处理到EOF。
给定r,n,m(2<=lt r,n,m<=t1234),分别表示卷积核大小,图像行数和列数,图像的每个元素均为0-255的整数,即灰度图。卷积核的大小永远为奇数。

输出

对于每组数据,输出均值模糊以后的图像。

输入样例

3 3 3
2 5 4
6 7 5
4 3 2

输出样例

4 4 4
4 4 4
4 4 3

分析:

先模拟边界的扩展,按照四边和四角来复制原始数组A,得到新的数组B(如下)
在这里插入图片描述
按照题目描述,计算模糊处理后的值,需要累加在图像上连续的r*r个元素,如果直接计算,需要最多计算1233^4次,99%会超时。
因此引入二维的前缀和方法:

定义:
对于二维数组B[m][n],(x1,y1)的前缀和=∑B[xi][yi], 0<=xi<=x1,0<=yi<=y1,即图像上该元素左上角的元素之和(包括该行该列)

由原数组计算前缀和数组:
在这里插入图片描述
如上图:sum[2][3] (蓝框内元素和) = sum[2][2] (绿框) +sum[1][4] (黄框)-sum[1][2] (绿框与黄框重合处多减了一次)
即:
sum[i][j] = sum[i - 1][j] + sum[i][j - 1] + b[i][j] - sum[i - 1][j - 1];

由前缀和数组计算连续的矩形框内元素和:
在这里插入图片描述
如上图:黄框=sum[3][4] -sum[3][2] - sum[1][4] +sum [1][2]

代码:
//多组输入输出
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int a[1300][1300];
int b[2500][2500];
int sum[2500][2500];
int res[1300][1300];
int main() {
	int r, n, m;
	int i, j, k;
	int i1, j1, k1;
	while (cin >> r >> n >> m) {
		memset(a, 0, sizeof(a));
		memset(b, 0, sizeof(b));
		memset(sum, 0, sizeof(sum));
		for (i = 1; i <= n; i++)
			for (j = 1; j <= m; j++)
				scanf("%d", &a[i][j]);
		int p = r / 2 + 1;
		for (i = p, i1 = 1; i < p + n; i++, i1++)
			for (j = p, j1 = 1; j < p + m; j++, j1++) {
				b[i][j] = a[i1][j1];
			}
		for (j = p; j < p + m; j++)//上 
			for (i = 1; i < p; i++)
				b[i][j] = b[p][j];
		for (j = p; j < p + m; j++)//下 
			for (i = n + p; i < n + r; i++)
				b[i][j] = b[n + p - 1][j];
		for (i = p; i < p + n; i++)//左 
			for (j = 1; j < p; j++)
				b[i][j] = b[i][p];
		for (i = p; i < p + n; i++)//右 
			for (j = p + m; j < m + r; j++)
				b[i][j] = b[i][m + p - 1];

		for (i = 1; i < p; i++)//左上 
			for (j = 1; j < p; j++)
				b[i][j] = b[p][p];
		for (i = n + p; i < n + r; i++)//左下 
			for (j = 1; j < p; j++)
				b[i][j] = b[n + p - 1][p];
		for (i = 1; i < p; i++)//右上 
			for (j = m + p; j < m + r; j++)
				b[i][j] = b[p][p + m - 1];
		for (i = n + p; i < n + r; i++)//右下
			for (j = m + p; j < m + r; j++)
				b[i][j] = b[n + p - 1][m + p - 1];

		for (i = 1; i <= n + r - 1; i++)//求二维前缀和 
			for (j = 1; j <= m + r - 1; j++)
				sum[i][j] = sum[i - 1][j] + sum[i][j - 1] + b[i][j] - sum[i - 1][j - 1];

		memset(res, 0, sizeof(res));
		for (i = p; i < n + p; i++)
			for (j = p; j < m + p; j++) { //(i-r/2-1,j-r/2-1)到(i+r/2,j+r/2)内的元素和
				res[i - p + 1][j - p + 1] = sum[i + r / 2][j + r / 2] - sum[i - r / 2 - 1][j + r / 2] - sum[i + r / 2][j - r / 2 - 1] + sum[i - r / 2 - 1][j - r / 2 - 1];
				res[i - p + 1][j - p + 1] /= r*r;
			}
		for (i = 1; i <= n; i++) {
			for (j = 1; j <= m; j++) {
				printf("%d", res[i][j]);
				if (j < m) printf(" ");
			}
			cout << endl;
		}
	}
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值