题目来源:http://poj.org/problem?id=1009

题目大意:

  某图像公司用run length encoding(RLE)的方式记录和存储了大量的图像。程序的目标是读入压缩后的图像,对图像进行边缘检测,然后输出另一幅压缩后的图片。具体形式见下面的图片和描述。

  一种最简单的边缘检测算法就是使输出图片像素点的值为输入图片中该像素点与其周围像素点值之间差值的最大值。考虑下面的例子:

Output image中左上角的像素点的值是|15-15|,|15-100|和|15-100|的最大值85.第4行第2列的像素点值是|175-100|,|175-100|,|175-100|,|175-175|,|175-25|,|175-175|,|175-175|和|175-25|的最小值150.

图像的像素点数在2至1,000,000,000(109)之间。所有的图片以RLE(run length encoding)的方式进行压缩编码。RLE是一些数据对,每对含一个像素值v和一个run length,即有连续多少个点的像素点的值为v。每幅图像最多含有1000个RLE对。连续的数据对的像素值都不相同。图像的每行像素点数相同。

输入:含一张或多张图像,每张图像信息的第一行为图像的宽度,接下来的每行为一个RLE对,以0 0结尾。图像宽度为0时表示图像数据输入完毕。Example Input展示的即为上图所示的图像。

输出:一系列边缘检测后的图像。与输入图像的格式相同,但运行RLE的数目多于1000.


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

刚开始直接用暴力方法做,发现数据量大时计算时间过长,TLE了。后来看了牛人的方法表示无比佩服。

  对于本题有如下观察:

  1.由于图片的像素点数最大为10^9,而RLE对的数目最大为1000,所以,一定存在一些RLE的run length很长,使得图像中有比较多的连续像素值相等,也即对他们的很多点进行边缘检测后的值一定为0,所以不必再逐个计算。

  2.实际上我们只需要关注结果值会与其前面的点不一样的点即可(取名为关键点),由这些关键点即可得到输出图像的RLE对。

  对于第2点,哪些点会是关键点呢?大牛分析后发现,每个输入的RLE对的起点和终点以及这些点周围的点一定包含了所有的关键点。如何证明?我没有去想怎么从理论上严格的推倒,只是从直觉上,我觉得可以这样来想象这个问题:

  首先把整幅图想象成一张白纸(比如把全部像素点的值初始化为0)。每读入一个RLE对,就相当于用彩笔在纸上给指定数目的像素点涂上了颜色。而每多涂一次颜色,该次涂色的起点和终点处及其周边的点的输出值会受到影响,有可能会变得跟其前一个点的输出值不一样(这个在纸上试一试就能发现),也就是说有可能成为关键点。而其他点的输出值应该是跟其左边的点输出值相等。所以当处理完了每个RLE对,也就把所有可能成为关键点的点的输出值都计算出来了。然后按坐标将所有点排序,再把输出值相等的点合并起来,就可以得到输出的RLE对。

  具体实现可以下列参考代码,但是效率可能不是很高,应该还可以继续优化。

 //////////////////////////////////////////////////////////////////////////
// POJ1009 Edgee Detection
// Memory: 656K Time: 172MS
// Language: C++ Result: Accepted
////////////////////////////////////////////////////////////////////////// #include <iostream>
#include <map>
#include <math.h>
#include <stdlib.h> #define getBigger(a, b) ((a > b) ? a : b)
#define upLeft(i) (i - c - 1)
#define up(i) (i - c)
#define upRight(i) (i - c + 1)
#define left(i) (i - 1)
#define right(i) (i + 1)
#define downLeft(i) (i + c - 1)
#define down(i) (i + c)
#define downRight(i) (i + c + 1) using namespace std; class RLE {
public:
int color;
int length;
int startPoint;
int endPoint;
}; RLE RLEList[];
int n;//RLE表长度
int pointCount; //总点数
int c, r;//image的列数与行数
map<int, int> PVmap; int getColor(int index) {
for(int i = ; i < n; i++) {
if (index <= RLEList[i].endPoint) {
return RLEList[i].color;
} else {
continue;
}
}
} int getValue(int i) {
int value = ; if ((upLeft(i) >= ) && ((i % c) > )) {
value = getBigger(value, abs(getColor(i) - getColor(upLeft(i))));
}
if ((up(i) >= )) {
value = getBigger(value, abs(getColor(i) - getColor(up(i))));
}
if ((upRight(i) >= ) && ((i % c) < c - )) {
value = getBigger(value, abs(getColor(i) - getColor(upRight(i))));
}
if ((left(i) >= ) && ((i % c) > )) {
value = getBigger(value, abs(getColor(i) - getColor(left(i))));
}
if ((right(i) <= r * c - ) && ((i % c) < c - )) {
value = getBigger(value, abs(getColor(i) - getColor(right(i))));
}
if ((downLeft(i) <= r * c - ) && ((i % c) > )) {
value = getBigger(value, abs(getColor(i) - getColor(downLeft(i))));
}
if ((down(i) <= r * c - )) {
value = getBigger(value, abs(getColor(i) - getColor(down(i))));
}
if ((downRight(i) <= r * c - ) && ((i % c) < c - )) {
value = getBigger(value, abs(getColor(i) - getColor(downRight(i))));
}
return value;
} void processPos(int index) {
if (PVmap.find(index) == PVmap.end()) {
PVmap[index] = getValue(index);
}
if (upLeft(index) >= && upLeft(index) < pointCount) {
if (PVmap.find(upLeft(index)) == PVmap.end()) {
PVmap[upLeft(index)] = getValue(upLeft(index));
}
}
if (up(index) >= && up(index) < pointCount) {
if (PVmap.find(up(index)) == PVmap.end()) {
PVmap[up(index)] = getValue(up(index));
}
}
if (upRight(index) >= && upRight(index) < pointCount) {
if (PVmap.find(upRight(index)) == PVmap.end()) {
PVmap[upRight(index)] = getValue(upRight(index));
}
}
if (left(index) >= && left(index) < pointCount) {
if (PVmap.find(left(index)) == PVmap.end()) {
PVmap[left(index)] = getValue(left(index));
}
}
if (right(index) >= && right(index) < pointCount) {
if (PVmap.find(right(index)) == PVmap.end()) {
PVmap[right(index)] = getValue(right(index));
}
}
if (downLeft(index) >= && downLeft(index) < pointCount) {
if (PVmap.find(downLeft(index)) == PVmap.end()) {
PVmap[downLeft(index)] = getValue(downLeft(index));
}
}
if (down(index) >= && down(index) < pointCount) {
if (PVmap.find(down(index)) == PVmap.end()) {
PVmap[down(index)] = getValue(down(index));
}
}
if (downRight(index) >= && downRight(index) < pointCount) {
if (PVmap.find(downRight(index)) == PVmap.end()) {
PVmap[downRight(index)] = getValue(downRight(index));
}
}
} int main(void) {
c = ;
while (true) {
cin >> c;
if (c == ) {
cout << "" << endl;
return ;
}
pointCount = ;
int i = ;
while (true) {
int color, length;
cin >> color >> length;
if (length == ) {
break;
}
RLEList[i].color = color;
RLEList[i].length = length;
i++;
pointCount += length;
}
r = pointCount / c;
if (pointCount % c) {
r++;
RLEList[i].length = r * c - pointCount;
RLEList[i].color = ;
pointCount = r * c;
i++;
}
n = i;
RLEList[].startPoint = ;
RLEList[].endPoint = RLEList[].length - ;
for (int i = ; i < n; i++) {
RLEList[i].startPoint = RLEList[i - ].startPoint + RLEList[i - ].length;
RLEList[i].endPoint = RLEList[i - ].endPoint + RLEList[i].length;
}
cout << c << endl;
//处理每个RLE对的起点和终点产生的影响
for (int RLEIndex = ; RLEIndex < n; RLEIndex++) {
int startPos = RLEList[RLEIndex].startPoint;
int endPos = RLEList[RLEIndex].endPoint;
processPos(startPos);
processPos(endPos);
}
map<int, int>::iterator it1;
map<int, int>::iterator it2;
int l = ;
//合并output image中相同的关键点,输出RLE对
for (it1 = PVmap.begin(), it2 = it1, ++it2; it2 != PVmap.end(); ++it1, ++it2) {
if((*it2).second == (*it1).second) {
l += (*it2).first - (*it1).first;
} else {
cout << (*it1).second << " " << l << endl;
l = ;
}
}
--it2;
cout << (*it2).second << " " << l << endl;
cout << "0 0"<< endl;
PVmap.clear();
}
return ;
}

 

POJ1009 Edge Detection的更多相关文章

  1. Edge detection using LoG

    intensity梯度值分布跟图片的大小有关, 比如将一张小图片放大后会变得很模糊, 原先清晰的edge, 即大的梯度值变得模糊. 但是原有的边缘通常还是肉眼可分辨的. 但用Sobel 算子可能就检测 ...

  2. 计算机视觉中的边缘检测Edge Detection in Computer Vision

    计算机视觉中的边缘检测   边缘检测是计算机视觉中最重要的概念之一.这是一个很直观的概念,在一个图像上运行图像检测应该只输出边缘,与素描比较相似.我的目标不仅是清晰地解释边缘检测是怎样工作的,同时也提 ...

  3. 【数字图像分析】基于Python实现 Canny Edge Detection(Canny 边缘检测算法)

    Canny 边缘检测算法 Steps: 高斯滤波平滑 计算梯度大小和方向 非极大值抑制 双阈值检测和连接 代码结构: Canny Edge Detection | Gaussian_Smoothing ...

  4. Image Processing and Analysis_21_Scale Space:Edge Detection and Ridge Detection with Automatic Scale Selection——1998

    此主要讨论图像处理与分析.虽然计算机视觉部分的有些内容比如特 征提取等也可以归结到图像分析中来,但鉴于它们与计算机视觉的紧密联系,以 及它们的出处,没有把它们纳入到图像处理与分析中来.同样,这里面也有 ...

  5. Image Processing and Analysis_8_Edge Detection:Edge Detection Revisited ——2004

    此主要讨论图像处理与分析.虽然计算机视觉部分的有些内容比如特 征提取等也可以归结到图像分析中来,但鉴于它们与计算机视觉的紧密联系,以 及它们的出处,没有把它们纳入到图像处理与分析中来.同样,这里面也有 ...

  6. Image Processing and Analysis_8_Edge Detection:Local Scale Control for Edge Detection and Blur Estimation——1998

    此主要讨论图像处理与分析.虽然计算机视觉部分的有些内容比如特 征提取等也可以归结到图像分析中来,但鉴于它们与计算机视觉的紧密联系,以 及它们的出处,没有把它们纳入到图像处理与分析中来.同样,这里面也有 ...

  7. Image Processing and Analysis_8_Edge Detection: Optimal edge detection in two-dimensional images ——1996

    此主要讨论图像处理与分析.虽然计算机视觉部分的有些内容比如特 征提取等也可以归结到图像分析中来,但鉴于它们与计算机视觉的紧密联系,以 及它们的出处,没有把它们纳入到图像处理与分析中来.同样,这里面也有 ...

  8. Image Processing and Analysis_8_Edge Detection:Multiresolution edge detection techniques ——1995

    此主要讨论图像处理与分析.虽然计算机视觉部分的有些内容比如特 征提取等也可以归结到图像分析中来,但鉴于它们与计算机视觉的紧密联系,以 及它们的出处,没有把它们纳入到图像处理与分析中来.同样,这里面也有 ...

  9. Image Processing and Analysis_8_Edge Detection:Scale-space and edge detection using anisotropic diffusion——1990

    此主要讨论图像处理与分析.虽然计算机视觉部分的有些内容比如特 征提取等也可以归结到图像分析中来,但鉴于它们与计算机视觉的紧密联系,以 及它们的出处,没有把它们纳入到图像处理与分析中来.同样,这里面也有 ...

随机推荐

  1. 【遍历二叉树】07恢复二叉搜索树【Recover Binary Search Tree】

    开一个指针数组,中序遍历这个二叉搜索树,将节点的指针依次保存在数组里, 然后寻找两处逆序的位置, 中序便利里BST得到的是升序序列 ++++++++++++++++++++++++++++++++++ ...

  2. [冬令营模拟]wzj的题目#1

    T1 少膜一个,T3 暴力写挂 强势 rank1 -> rank2 一场比赛两道线段树分治,给力 T1 password 给你 m 个禁止字符串,求长度为 n 的所有字符串中至少包含这些禁止字符 ...

  3. 20179203 《Linux内核原理与分析》第十周作业

    第17章 设备与模块 一.设备类型 1. Linux及Unix系统: 块设备 字符设备 网络设备 2.块设备: 通常缩写为blkdev,它是可寻址的,寻址以块为单位,块大小随设备不同而不同:块设备通常 ...

  4. [SPOJ-DISUBSTR]Distinct Substrings

    vjudge 题意 给你一个串,求不同字串个数. \(n\le10^5\) sol 直接建SAM然后输出\(\sum_{i=1}^{tot}len[i]-len[fa[i]]\) code #incl ...

  5. gradle项目搭建

    一.gradle安装 1.安装JDK,这个就不用说了 2.下载gradle发布文件,下载地址:http://gradle.org/gradle-download/可以下载完整版或者简洁版都可以 3.解 ...

  6. VIJOS:P1706(舞会)

    描述 Arthur公司是一个等级森严的公司,它们有着严格的上司与下属的关系,公司以总裁为最高职位,他有若干个下属,他的下属又有若干个下属,他的下属的下属又有若干个下属……现接近年尾,公司组织团拜活动, ...

  7. 【转】 Pro Android学习笔记(七十):HTTP服务(4):SOAP/JSON/XML、异常

    目录(?)[-] SOAP JSON和XMLPullParser Exception处理 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件,转载须注明出处:http://blog. ...

  8. Windows部署jenkins服务器

    本次使用的操作系统: windows server 2012 r2vs版本: vs 2015jenkins: 2.19.4 一.下载jenkins http://mirror.xmission.com ...

  9. 删除eclipse Maven 进程 导致eclipse的workspace 启动不了

    异常描述: An internal error occurred during: "reload maven project". java.lang.NullPointerExce ...

  10. 10个C语言经典

    1.计算Fibonacci数列Fibonacci数列又称斐波那契数列,又称黄金分割数列,指的是这样一个数列:1.1.2.3.5.8.13.21.C语言实现的代码如下: /* t3ing Fibonac ...