视线逐渐模糊
描述
均值模糊算法的具体流程如下:
给定一张图片,使用一个卷积核在图像上进行卷积操作,得到一张新的图片。其中卷积核为长宽均为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;
}