poj1009 -- Edge Detection

Edge Detection
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 21730 Accepted: 5099

Description

IONU Satellite Imaging, Inc. records and stores very large images using run length encoding. You are to write a program that reads a compressed image, finds the edges in the image, as described below, and outputs another compressed image of the detected edges. 
A simple edge detection algorithm sets an output pixel's value to be the maximum absolute value of the differences between it and all its surrounding pixels in the input image. Consider the input image below: 

The upper left pixel in the output image is the maximum of the values |15-15|,|15-100|, and |15-100|, which is 85. The pixel in the 4th row, 2nd column is computed as the maximum of |175-100|, |175-100|, |175-100|, |175-175|, |175-25|, |175-175|,|175-175|, and |175-25|, which is 150. 
Images contain 2 to 1,000,000,000 (10 9) pixels. All images are encoded using run length encoding (RLE). This is a sequence of pairs, containing pixel value (0-255) and run length (1-10 9). Input images have at most 1,000 of these pairs. Successive pairs have different pixel values. All lines in an image contain the same number of pixels. 

Input

Input consists of information for one or more images. Each image starts with the width, in pixels, of each image line. This is followed by the RLE pairs, one pair per line. A line with 0 0 indicates the end of the data for that image. An image width of 0 indicates there are no more images to process. The first image in the example input encodes the 5x7 input image above. 

Output

Output is a series of edge-detected images, in the same format as the input images, except that there may be more than 1,000 RLE pairs. 

Sample Input

7
15 4
100 15
25 2
175 2
25 5
175 2
25 5
0 0
10
35 500000000
200 500000000
0 0
3
255 1
10 1
255 2
10 1
255 2
10 1
255 1
0 0
0

Sample Output

7
85 5
0 2
85 5
75 10
150 2
75 3
0 2
150 2
0 4
0 0
10
0 499999990
165 20
0 499999990
0 0
3
245 9
0 0
0

Hint

A brute force solution that attempts to compute an output value for every individual pixel will likely fail due to space or time constraints. 

看到这一题后我唯一的思路就是暴力求解,但暴力求解显然是行不通的,因为图像最多会有10亿个像素,把他们全部存储下来会超内存,运行起来也会TLE,题目中的Hint也告诉我们不要暴力求解。之后上网看了几篇博客,发现大家使用的方法叫做“跳跃式编码”,首先存储时不是把所有的像素都存储下来,而是只存储输入的数据,即像素值和值出现的次数,其次我们先假设像素是线性排列,给每一个像素编号依次编号,然后根据编号和题目输入给出的width求出其在二维数组(即图像)中的行和列,具体的方法如下:

(1)找出每一次像素发生变化的位置posInLine,举个例子假如像素值为0 ,0 , 0, 1 ,1 ,1则变化的位置为第一个0的位置0和第一个1的位置3,将变化的位置转化为二维数组中的行row和列col;

(2)求出(row,col)及其周围共9个点的像素值编码code与位置pos,求解方法题目中已给出,并存储下来,我的代码中存在了vector类型的result中;

(3)找出下一个像素发生变化的位置,即把当前变化的位置加上当前值的个数,重复(2)直至所有的输入对都处理完成;

(4)按pos从小到大对result进行排序后输出。

这里还有一点需要注意,比如我使用vector来存储输入的数据,假设输入的数据为:

7
15 4
100 15
25 2
175 2
25 5
175 2
25 5
0 0

则共输入了7对数据,我们将这7组数据输入之后还要在数组的最后加上"0 1"这一组数据,可以配合这样一组输入数据来理解:
输入:

30
10 41
20 41
15 41
30 41
25 41
0 5
0 0
0

输出应为:

30
0 10
10 62
5 20
15 62
5 20
25 6
5 15
0 9
25 6
0 0
0

我就是因为这个问题卡了很久。

具体代码如下:

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;

struct Pair		
{
	int value;	//输入的值
	int times;	//value的个数

	Pair(int v, int t) :value(v), times(t) {}
};

struct Result
{
	int code;	//编码
	int pos;	//code的个数

	Result(int c, int p) :code(c), pos(p) {}
};

bool cmp(Result r1, Result r2)	//将result按pos从小到大排序
{
	return r1.pos<r2.pos;
}

vector<Pair> pairs;
vector<Result> result;
int width = 0;
int total = 0;	//像素的总个数

int getValue(int pos)	//获得pos位置的像素值
{
	int p = 0, i = 0;
	while (p<=pos)
		p += pairs[i++].times;
	return pairs[--i].value;
}

int encode(int row, int col)	//编码函数
{
	int posInLine = row*width + col;
	int centerValue = getValue(posInLine);
	int maxValue = 0;

	for (int i = row - 1;i <= row + 1;i++)
		for (int j = col - 1;j <= col + 1;j++)
		{
			int pos = i*width + j;
			if (i<0 || j<0 || j>=width || pos == posInLine || pos >= total)
				continue;
			int arroundValue = getValue(pos);
			int value = abs(centerValue - arroundValue);
			maxValue = value>maxValue ? value : maxValue;
		}
	return maxValue;
}

int main()
{
	//freopen("test.txt", "r", stdin);
	while (scanf("%d", &width) == 1 && width)
	{
		pairs.clear();
		result.clear();
		total = 0;
		printf("%d\n", width);
		int value, times;
		while (scanf("%d%d", &value, ×) && (value||times))	//输入数据
		{
			pairs.push_back(Pair(value, times));
			total += times;
		}
		pairs.push_back(Pair(0, 1));	//这一步尤其注意

		for (int i = 0;i<pairs.size();i++)	//遍历vector,如果使用普通数组存储,则不应使用<,而应该<=
		{
			int row = curPos / width;
			int col = curPos % width;
			for (int j = row - 1;j <= row + 1;j++)
				for (int k = col - 1;k <= col + 1;k++)
				{
					int posInLine = j*width + k;	//获取行为j,列为k的像素编号
					if (j<0 || k<0 || k >= width || posInLine >= total)
						continue;
					int code = encode(j, k);
					result.push_back(Result(code, posInLine));	//将编码后的像素存入result
				}
			curPos += pairs[i].times;	//跳到下一个像素变化点
		}
		sort(result.begin(), result.end(), cmp);	//将result按pos从小到大排序
		/*for (int i = 0;i < result.size();i++)
			cout << result[i].code << " " << result[i].pos << endl;*/
		Result cur = result[0];		//输出
		for (int i = 0;i<result.size();i++)
		{
			if (cur.code == result[i].code)
				continue;
			printf("%d %d\n", cur.code, result[i].pos - cur.pos);
			cur = result[i];
		}
		printf("%d %d\n", cur.code, total - cur.pos);
		printf("0 0\n");
	}
	printf("0\n");	//注意最后输出0
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值