试题背景
顿顿在学习了数字图像处理后,想要对手上的一副灰度图像进行降噪处理。不过该图像仅在较暗区域有很多噪点,如果贸然对全图进行降噪,会在抹去噪点的同时也模糊了原有图像。因此顿顿打算先使用邻域均值来判断一个像素是否处于较暗区域,然后仅对处于较暗区域的像素进行降噪处理。
问题描述
待处理的灰度图像长宽皆为 n 个像素,可以表示为一个 n×n 大小的矩阵 A,其中每个元素是一个 [0,L) 范围内的整数,表示对应位置像素的灰度值。
对于矩阵中任意一个元素 Aij(0≤i,j<n),其邻域定义为附近若干元素的集和:
Neighbor(i,j,r)={Axy|0≤x,y<n and |x−i|≤r and |y−j|≤r}
这里使用了一个额外的参数 r 来指明 Aij 附近元素的具体范围。根据定义,易知 Neighbor(i,j,r) 最多有 (2r+1)2 个元素。
如果元素 Aij 邻域中所有元素的平均值小于或等于一个给定的阈值 t,我们就认为该元素对应位置的像素处于较暗区域。
现给定邻域参数 r 和阈值 t,试统计输入灰度图像中有多少像素处于较暗区域。
输入格式
输入共 n+1 行。
输入的第一行包含四个用空格分隔的正整数 n、L、r 和 t,含义如前文所述。
第二到第 n+1 行输入矩阵 A。
第 i+2(0≤i<n)行包含用空格分隔的 n 个整数,依次为 Ai0,Ai1,⋯,Ai(n−1)。
输出格式
输出一个整数,表示输入灰度图像中处于较暗区域的像素总数。
样例输入
4 16 1 6
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
样例输出
7
样例输入
11 8 2 2
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 7 0 0 0 7 0 0 7 7 0
7 0 7 0 7 0 7 0 7 0 7
7 0 0 0 7 0 0 0 7 0 7
7 0 0 0 0 7 0 0 7 7 0
7 0 0 0 0 0 7 0 7 0 0
7 0 7 0 7 0 7 0 7 0 0
0 7 0 0 0 7 0 0 7 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
样例输出
83
评测用例规模与约定
70% 的测试数据满足 n≤100、r≤10。
全部的测试数据满足 0<n≤600、0<r≤100 且 2≤t<L≤256。
思路分析
规模中有数据的限制,暴力无法解决,看暴力的代码就明白,每一次计算都会有重复的数被多次计算,刚开始考虑用四维数组表示从(x1,y1)到(x2,y2)的数据总和,但是在思考后放弃,因为这样又成了重复计算,然后考虑到可以用二维数组存放从(1,1)(x1,y1)的数据和,而利用该二维数组计算每一部分的值。
将每一次的值与t相减,最后所有邻域内的值相加,若小于等于0则为暗色,否则则不为。
一个简单的前缀和例子
sum[i] = a[i] + sum[i - 1];
代码
#include<iostream>
using namespace std;
#define max( a, b) ( a > b ? a : b)
#define min( a, b) ( a < b ? a : b)
int const N = 600 + 1;
int A[N][N];
int sum[N][N];
bool isblack(int x,int y,int n,int r,int t){ // <= 0 --> true
int x1 = min(x + r,n);
int y1 = min(y + r,n);
int x2 = max(x - r,1);
int y2 = max(y - r,1);
int ans = sum[x1][y1] - sum[x2 - 1][y1] - sum[x1][y2 - 1] + sum[x2 - 1][y2 - 1];
if(ans <= 0){
return true;
}else{
return false;
}
}
int main(){
int n,L,r,t;
cin>>n>>L>>r>>t;
for(int i = 1;i <= n;i++){
for(int j = 1;j <= n;j++){
cin>>A[i][j];
A[i][j] -= t;
sum[i][j] = sum[i][j-1] + sum[i-1][j] - sum[i- 1][j - 1] + A[i][j];
}
}
int ans = 0;
for(int i = 1;i <= n;i++){
for(int j = 1;j <= n;j++){
if(isblack(i,j,n,r,t)){
ans++;
}
}
}
cout<<ans<<endl;
}