试题背景
顿顿在学习了数字图像处理后,想要对手上的一副灰度图像进行降噪处理。不过该图像仅在较暗区域有很多噪点,如果贸然对全图进行降噪,会在抹去噪点的同时也模糊了原有图像。因此顿顿打算先使用邻域均值来判断一个像素是否处于较暗区域,然后仅对处于较暗区域的像素进行降噪处理。
问题描述
待处理的灰度图像长宽皆为 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,试统计输入灰度图像中有多少像素处于较暗区域。
【样例】......
评测用例规模与约定
70% 的测试数据满足 n≤100、r≤10。
全部的测试数据满足 0<n≤600、0<r≤100 且 2≤t<L≤256。
【思路】
暴力只能过60%
所以要用二维前缀和,num[i][j]指的是从(1,1)到(i,j)的区域的数和;
由此:任意一个以(left,top)到(right,under)的区域内的总值可以算出由num数组算出
int value=num[under][right]-num[top-1][right]-num[under][left-1]+num[top-1][left-1];
S1 | S2 |
S3 | Value |
Value = (S1+S2+S3+S4) - (S1 + S2)- (S1+ S3) + S1;
【AC代码】
#include<iostream>
#include<string.h>
using namespace std;
int a[610][610];
int num[610][610];
int n;
int res;
int L;
int r;
int t;
// 二维前缀和
//任何一个区域(x1,y1)到(x2,y2)的灰度数量 = (0,0)到(x2,y2)的数量减去其余三个位置的数量
int main(){
cin>>n>>L>>r>>t;
for(int i=0;i<=n;i++){ //预留1行1列 非常方便
for(int j=0;j<=n;j++){
if(i==0||j==0){
a[i][j]=0;
num[i][j]=0;
continue;
}
cin>>a[i][j];
}
}
for(int i=1;i<=n;i++){ //num[i][j]是0,0到i,j的总和
for(int j=1;j<=n;j++){
num[i][j]=num[i-1][j]+num[i][j-1]+a[i][j]-num[i-1][j-1];
}
}
// for(int i=1;i<=n;i++){
// for(int j=1;j<=n;j++){
// cout<<num[i][j]<<" ";
// }
// cout<<'\n';
// }
int res=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
int top=max(1,i-r);
int under=min(n,i+r);
int left=max(1,j-r);
int right=min(n,j+r);
int num_p=(right-left+1)*(under-top+1);
int value=num[under][right]-num[top-1][right]-num[under][left-1]+num[top-1][left-1];
//注意是错开的
if((value*1.0)/num_p <= t) res++; //这里乘个1.0 自动变成了浮点数!!
//一切都向浮点数转化后进行
}
}
cout<<res;
}
【写在后面】
有啥问题就评论区或者私我都行~给个赞吧~