CCF 2021-04-2 邻域均值

试题背景

顿顿在学习了数字图像处理后,想要对手上的一副灰度图像进行降噪处理。不过该图像仅在较暗区域有很多噪点,如果贸然对全图进行降噪,会在抹去噪点的同时也模糊了原有图像。因此顿顿打算先使用邻域均值来判断一个像素是否处于较暗区域,然后仅对处于较暗区域的像素进行降噪处理。

问题描述

待处理的灰度图像长宽皆为 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;
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值