试题链接:首页 - 计算机软件能力认证考试系统
【试题背景】
顿顿在学习了数字图像处理后,想要对手上的一副灰度图像进行降噪处理。不过该图像仅在较暗区域有很多噪点,如果贸然对全图进行降噪,会在抹去噪点的同时也模糊了原有图像。因此顿顿打算先使用邻域均值来判断一个像素是否处于较暗区域,然后仅对处于较暗区域的像素进行降噪处理。
【问题描述】
待处理的灰度图像长宽皆为 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)。
【输出形式】输出一个整数,表示输入灰度图像中处于较暗区域的像素总数。
【样例1输入】
4 16 1 6
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
【样例1输出】7
【样例2输入】
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
【样例2输出】
83
这道题就是用二维前缀和
首先初始化二维前缀和数组
int b[n+1][n+1];
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
int cur;
cin>>cur;
b[i][j]=b[i-1][j]+b[i][j-1]-b[i-1][j-1]+cur;
}
}
之后就是遍历每一个像素点,计算该像素点所在邻域内,所有点的像素之和,并计算平均值;
然后将平均值(aver)与t进行比对,如果aver小于等于t,则处于暗区域的像素点个数(num)++;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
//求邻域左右边界值
int lefti=max(1,i-r),righti=min(n,i+r),leftj=max(1,j-r),rightj=min(n,j+r);
//求邻域内值
int sum=b[righti][rightj]-b[righti][leftj-1]-b[lefti-1][rightj]+b[lefti-1][leftj-1];
//求平均值
double aver=sum/((righti-lefti+1)*(rightj-leftj+1)*1.0);
if(aver<=t) num++;
}
}
最后输出num即可。
总的代码
#include <iostream>
using namespace std;
int main()
{
int n,L,r,t,num=0;
cin>>n>>L>>r>>t;
int b[n+1][n+1];
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
int cur;
cin>>cur;
b[i][j]=b[i-1][j]+b[i][j-1]-b[i-1][j-1]+cur;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
//求邻域左右边界值
int lefti=max(1,i-r),righti=min(n,i+r),leftj=max(1,j-r),rightj=min(n,j+r);
//求邻域内值
int sum=b[righti][rightj]-b[righti][leftj-1]-b[lefti-1][rightj]+b[lefti-1][leftj-1];
//求平均值
double aver=sum/((righti-lefti+1)*(rightj-leftj+1)*1.0);
if(aver<=t) num++;
}
}
cout<<num;
return 0;
}
参考大佬文章: