8.13.1 Kind of a Blur

题目描述

当被拍摄物偏离出焦距以外,成像模糊,就会造成失焦。对给出的模糊的原始图像进行恢复是图像处理中最有趣的课题之一。这一过程被称为去模糊,这也是本题要求您解决的任务。

在本题中,所有的图像都是灰色的(没有颜色);一个图像表示为一个实数的二维矩阵,其中每个单元是对应像素的亮度。虽然在数学上讲并不精确,但是,一个清晰的图像被模糊化,就是将距离每个像素(包括该像素本身)的某个曼哈顿距离内(小于或等于)的所有像素的值取平均值,赋给这个像素。下面是一个如何计算模糊距离为 1 的 3×3 图像的模糊度的示例:

本题给出一个图像的模糊版本,要求恢复原始图像的版本。本题设定给出的图像是模糊的,如上所述。 两点之间的曼哈顿距离(也被称为出租车距离)是它们坐标的绝对值的差的总和。 下面的网格给出了与灰色单元格之间的曼哈顿距离。

输入输出格式

输入格式 输入包含若干测试用例。每个测试用例 H+1 行,第一行给出三个非负整数,分别表示模糊图像的宽度 W,高度 H,以及模糊距离 D,其中,1≤W,H≤10,且 D≤min(W/2,H/2)。接下来的 H 行给出模糊图像中每个像素的灰度,每行给出 W 个非负实数,实数保留小数点后两位,所有给出的实数值都小于 100。 在测试用例之间可能是零行,也可能有多行(完全由空格组成)。输入的最后一行由三个零组成。

输出格式 对于每个测试用例,输出一个 W×H 的实数矩阵,表示图像的去模糊之后的版本。矩阵中的每个元素精确到两位小数,并在宽度为 8 的字段中向右对齐。用一个空行分隔两个连续的测试用例的输出。在最后一个测试用例之后不要输出空行。本题设定每个测试用例都有一个唯一的解。

输入输出样例1

输入

 
  1. 2 2 1
  2. 1 1
  3. 1 1
  4. 3 3 1
  5. 19 14 20
  6. 12 15 18
  7. 13 14 16
  8. 4 4 2
  9. 14 15 14 15
  10. 14 15 14 15
  11. 14 15 14 15
  12. 14 15 14 15
  13. 0 0 0

输出

 
  1. 1.00 1.00
  2. 1.00 1.00
  3. 2.00 30.00 17.00
  4. 25.00 7.00 13.00
  5. 14.00 0.00 35.00
  6. 1.00 27.00 2.00 28.00
  7. 21.00 12.00 17.00 8.00
  8. 21.00 12.00 17.00 8.00
  9. 1.00 27.00 2.00 28.00
     #include <iostream>
    #include <cstring>
    #include <cmath>
    #include <iomanip>
    #define endl '\n'
    #define IOS ios::sync_with_stdio(false);
    using namespace std;
     
    typedef long long ll;
     
    const double eps = 1e-8;
    bool isFirst = true;
     
    struct Matrix
    {
    	int h, w;
    	double m[105][105];
    	
    	void init(int totalh, int totalw)
    	{
    		h = totalh;
    		w = totalw;
    		memset(m, 0, sizeof m);
    	}
    	
    	void Guass()
        {
            for (int i = 0 ; i < h-1 ; i++)
            {
                //交换行(减小误差) 
                int t = i;
                for (int j = i+1 ; j < h ; j++)
                {
                    if (fabs(m[j][i]) > fabs(m[t][i]))
                        t = j;
                }
                if (t != i)
                {
                    for (int j = 0 ; j < w ; j++)
                        swap(m[t][j],m[i][j]);
                }
     
                //消元
                for (int j = i+1 ; j < h ; j++)
                {
                    if (fabs(m[j][i]) < eps)
                        continue;
                    double mul = m[j][i] / m[i][i];
                    for (int k = i ; k < w ; k++)
                        m[j][k] -= m[i][k] * mul;
                }
            }
     
            //反向求解
            for (int i = h-1 ; i >= 0 ; i--)
            {
                if (fabs(m[i][i]) < eps)
                    continue;
                for (int j = i+1 ; j < h ; j++)
                    m[i][w-1] -= m[i][j]*m[j][w-1];
                m[i][w-1] /= m[i][i];
            }
        }   
    };
     
    int main()
    {
    	//IOS; cin.tie(0), cout.tie(0);
    	int w, h, d;
    	double a[15][15];
    	while (cin >> w >> h >> d)
    	{
    		if (w == 0 && h == 0 && d == 0)
    			break; 
    		for (int i = 0; i < h; ++i)
    		{
    			for (int j = 0; j < w; ++j)
    			{
    				cin >> a[i][j];
    			}
    		}
    		
    		if (isFirst)
    		{
    			isFirst = false;
    		}
    		else
    		{
    			cout << endl;
    		}
    		
    		Matrix ans;
    		ans.init(h * w, h * w + 1); 
    		
    		//高斯消元的不可少的步骤
    		for (int i = 0; i < h; ++i)
    		{
    			for (int j = 0; j < w; ++j)
    			{
    				int cnt = 0;	//记录一个点的曼哈顿距离能够到达的个数
    				for (int k = i - d; k <= i + d; ++k)	//枚举能到达的行 
    				{
    					if (k < 0 || k >= h)
    						continue;
    					int left = d - abs(i - k);
    					for (int l = j - left; l <= j + left; ++l)
    					{
    						if (l < 0 || l >= w)
    							continue;
    						cnt++;
    						ans.m[i * w + j][k * w + l] = 1;	//第i * w + j行方程的第k * w + l	
    					} 
    				} 
    				ans.m[i * w + j][h * w] = cnt * a[i][j]; 
    			}
    		} 
    		ans.Guass();
    		
    		for (int i = 0 ; i < h ; ++i)
            {
                for (int j = 0 ; j < w ; ++j)
                    printf ("%8.2lf",ans.m[i * w + j][ans.w - 1]);
                printf ("\n");
            }
    	}
    	return 0;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值