Edge Detection
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 22604 | Accepted: 5311 |
Description
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 (109) 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-109). 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
Output
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
Source
题意
使用一种叫做“run length encoding”的方式来储存大尺寸图片,该方法是通过记录编码值和编码长度的对(number,length)来存储图片。有一种简单的edge detection算法是将图像中的每一个点的值与他周围的八个点求差,然后取绝对值的最大值。
现在的任务就是实现这个算法,输入的图片是以run length encoding的形式表示的,同时也要求转换后的图片也以run length encoding的形式表示。
思路
题意中说明图片的长度为10^9,因此不可能采用暴力计算法。从答案中可以看出,会有连续一段的相同输入输出,输入的pair number不超过1000,数量上是很少的,因此可以采用跳跃编码。
run length encoding编码方法是记录编码值和该值的编码长度,这里长度可以用开始和结束位置代替,结束位置可以用下一个值的开始位置表示。这样就变成记录每一个出现的新值和出现的位置即可。
而edge detection中每一个新值的出现都是因为输入图片中新值的出现。因此,只要对输入图片的每一个pair计算这个新值开始位置周围8个像素值,并记录位置即可。然后对所有计算的像素值根据位置排序,并且对像素值相同的格子进行合并就是所求结果。
上图来自 POJ 1009 Edge Detection(图像边缘检测)
我们使用跳跃编码,记录起始格子的num值和它的长度len,自然可以通过计算得到一个虚拟很长的输入或是输出数组(一维),再将一维数组转换为虚拟二维数组,即对len进行累加,即为一维数组的索引值,像素值num即为一位数组中存储的值,而转换为二维数组,即为一位数组索引值对n取余或是取整,之所以说是虚拟,就是不开辟空间进行存储……
考虑到这里,想到了使用map,map<int,int>,其中只存储连续段的起始格,对于输入map<int,int> InMap和输出map<int,int> OutMap,其key值用来存储一位数组的索引值,value则用来存储像素值num,为什么用map呢,最重要的是它可以按照key值自动升序排列,计算每一个连续段起始格周围的8个格子后,将计算得到的像素值和数组索引值插入map,他自动帮我们按照数组索引值排序了,这样,当我们计算完毕之后,向前迭代输出,省去了排序吧啦吧啦的麻烦,只要向前迭代,并把像素值相同的格子忽略掉(因为他们应该属于同一连续段的)就可以了。本小白感觉map大法好!
关于map==》C++ STL 中 map 容器
这时候,需要考虑一下特殊的格子,对于在二维数组边界的格子,他的周围不足8个格子,计算的时候当然要注意。
我们可以用简单的取余运算就把在最左边一列、最右边一列给筛选出来。这里我们把连续段的长度进行求和为Max,即数组索引从0开始,且最大索引值不会超过Max,所以可以把最上面一行和最下面一行计算中的越界格子排掉。这里需要考虑到每行只有一列和两列的情况!!
还有更值得我们注意的!!这里也让本小白WA了几次,百思不得其解了好久……
那就是最后一行的第一个格子,由于它没有下一行,所以它的像素值会发生变化
有朋友问为什么最后一行的第一个格子需要考虑而别的行的第一个格子不需要考虑呢?
首先,如果像这样像素值发生变化,自然会进行计算。
其次,如果像素值没有发生变化,那无非就是担心换行之后,格子上方和下方的格子的数值变化,拿上方格子数值变化为例,如果两个格子(黄色)上方格子数值不一样,那紫色格子的数值发生变化时,必然会计算黄色格子的数值,所以此处不需计算。其他情况同理。
而最下面一行的第一个格子,它的下面的格子不是数值发生变化,而是消失了,即可以理解为,它下面的格子数值发生了变化但是不会启动计算过程,所以最下面一行的第一个格子是特殊的。
#include<iostream>
#include<map>
using namespace std;
/*
可以利用map<int,int>的first为下标,second为像素值
一个输入map,一个输出map
利用map的特性,输出map插入后自动以first排序
输出的时候遍历输出map,如果second不同,则进行输出 代码很乱包括了我的测试代码……
*/
void Print(map<int,int> OutMap,int n,int Max)
{
long tempFirst = ,tempSecond=;
/*
map<int,int>::iterator iter = OutMap.begin();
for(iter;iter != OutMap.end();iter++)
{
cout<<iter->first<<" "<<iter->second<<endl;
}
*/
map<int,int>::iterator iter1 = OutMap.begin();//向前迭代
tempFirst = iter1->first;tempSecond = iter1->second;
for(iter1;iter1 != OutMap.end();iter1++)
{
if(iter1->second != tempSecond)
{
cout<<tempSecond<<" "<<iter1->first-tempFirst<<endl; tempSecond = iter1->second;
tempFirst = iter1->first;
}
}
cout<<tempSecond<<" "<<Max-tempFirst<<endl; cout<<<<" "<<<<endl;
}
void Compute(map<int,int> In,int n,int Max)
{//计算输出数组
/**/
map<int,int> OutMap;
int Count=;//记录数组下
int temp=;
int arr[] = {,-n-,-n,-n+,-,,n-,n,n+,Max-n};
///对In进行遍历
map<int,int>::iterator iter = In.begin();
for(iter;iter != In.end();iter++)
{
for(int i=;i<;i++)
{
if(i == ) Count = arr[i];
else Count = iter->first + arr[i];//周围8个像素的下标,包括自己
if(Count < || Count >= Max)
{//下标越界
continue;
}
else if(Count%n == n- && iter->first%n == && n!=&& n!=)
{//在最左边一列,没有左边像素
continue;
}
else if(Count%n == && iter->first%n == n- && n!=&& n!=)
{//在最右边一列,没有右边像素
continue;
}
else{
map<int,int>::iterator CountIter = In.begin();//指针定位到中心
CountIter = In.upper_bound(Count);
CountIter--;
//cout<<"测试CountIter:"<<CountIter->first<<" "<<CountIter->second<<endl;
///计算当前像素的值
int Num = ;
int tempNum = ;
for(int j =;j<;j++)//考察周围的八个点
{
temp = Count + arr[j];
if(temp< || temp>=Max || temp%n==n-&&Count%n==&&n!= || temp%n==&&Count%n==n-&&n!=)
{
continue;
}else{
map<int,int>::iterator tempIter;
tempIter = In.upper_bound(temp);//第一个大于temp的位置
//cout<<"测试tempIter:"<<tempIter->first<<" "<<tempIter->second<<endl;
tempIter--;
//cout<<"测试tempIter2:"<<tempIter->first<<" "<<tempIter->second<<endl;
tempNum = CountIter->second - tempIter->second;
if(tempNum < ) tempNum = - * tempNum;
}
if(tempNum > Num) Num = tempNum;
}
///插入到OutMap
OutMap.insert(pair<int,int>(Count,Num));
}
}
}
Print(OutMap,n,Max);
OutMap.clear();
} int main()
{
int n;
map<int,int> InMap; cin>>n;
cout<<n<<endl;
while(n)
{ int num,len;
long Count = ;
///获取输入数组
cin>>num>>len;
while(len)
{
InMap.insert(pair<int,int>(Count,num));
Count += len;//虚拟数组下标增加
cin>>num>>len;
}
InMap.insert(pair<int,int>(,));
/*
map<int,int>::iterator iter;//向前迭代
for(iter = InMap.begin();iter != InMap.end();iter++)
{
cout<<iter->first<<","<<iter->second<<endl;
}
*/
///输入结束,进行输出数组的计算
Compute(InMap,n,Count);
InMap.clear();
cin>>n;
cout<<n<<endl;
} return ;
}
Edge Detection的更多相关文章
- Edge detection using LoG
intensity梯度值分布跟图片的大小有关, 比如将一张小图片放大后会变得很模糊, 原先清晰的edge, 即大的梯度值变得模糊. 但是原有的边缘通常还是肉眼可分辨的. 但用Sobel 算子可能就检测 ...
- 计算机视觉中的边缘检测Edge Detection in Computer Vision
计算机视觉中的边缘检测 边缘检测是计算机视觉中最重要的概念之一.这是一个很直观的概念,在一个图像上运行图像检测应该只输出边缘,与素描比较相似.我的目标不仅是清晰地解释边缘检测是怎样工作的,同时也提 ...
- 【数字图像分析】基于Python实现 Canny Edge Detection(Canny 边缘检测算法)
Canny 边缘检测算法 Steps: 高斯滤波平滑 计算梯度大小和方向 非极大值抑制 双阈值检测和连接 代码结构: Canny Edge Detection | Gaussian_Smoothing ...
- Image Processing and Analysis_21_Scale Space:Edge Detection and Ridge Detection with Automatic Scale Selection——1998
此主要讨论图像处理与分析.虽然计算机视觉部分的有些内容比如特 征提取等也可以归结到图像分析中来,但鉴于它们与计算机视觉的紧密联系,以 及它们的出处,没有把它们纳入到图像处理与分析中来.同样,这里面也有 ...
- Image Processing and Analysis_8_Edge Detection:Edge Detection Revisited ——2004
此主要讨论图像处理与分析.虽然计算机视觉部分的有些内容比如特 征提取等也可以归结到图像分析中来,但鉴于它们与计算机视觉的紧密联系,以 及它们的出处,没有把它们纳入到图像处理与分析中来.同样,这里面也有 ...
- Image Processing and Analysis_8_Edge Detection:Local Scale Control for Edge Detection and Blur Estimation——1998
此主要讨论图像处理与分析.虽然计算机视觉部分的有些内容比如特 征提取等也可以归结到图像分析中来,但鉴于它们与计算机视觉的紧密联系,以 及它们的出处,没有把它们纳入到图像处理与分析中来.同样,这里面也有 ...
- Image Processing and Analysis_8_Edge Detection: Optimal edge detection in two-dimensional images ——1996
此主要讨论图像处理与分析.虽然计算机视觉部分的有些内容比如特 征提取等也可以归结到图像分析中来,但鉴于它们与计算机视觉的紧密联系,以 及它们的出处,没有把它们纳入到图像处理与分析中来.同样,这里面也有 ...
- Image Processing and Analysis_8_Edge Detection:Multiresolution edge detection techniques ——1995
此主要讨论图像处理与分析.虽然计算机视觉部分的有些内容比如特 征提取等也可以归结到图像分析中来,但鉴于它们与计算机视觉的紧密联系,以 及它们的出处,没有把它们纳入到图像处理与分析中来.同样,这里面也有 ...
- Image Processing and Analysis_8_Edge Detection:Scale-space and edge detection using anisotropic diffusion——1990
此主要讨论图像处理与分析.虽然计算机视觉部分的有些内容比如特 征提取等也可以归结到图像分析中来,但鉴于它们与计算机视觉的紧密联系,以 及它们的出处,没有把它们纳入到图像处理与分析中来.同样,这里面也有 ...
- Image Processing and Analysis_8_Edge Detection:A Computational Approach to Edge Detection——1986
此主要讨论图像处理与分析.虽然计算机视觉部分的有些内容比如特 征提取等也可以归结到图像分析中来,但鉴于它们与计算机视觉的紧密联系,以 及它们的出处,没有把它们纳入到图像处理与分析中来.同样,这里面也有 ...
随机推荐
- 一个div多个图表共用一个图例
想实现一个图例(公司名),点击让div中三个图表进行显示相应的数据,并渲染到图表中(公司数据可能很多,让其默认显示三条数据),并且每个图表都有相应的标题和datazoom区域展示,点击下拉框会进行相应 ...
- iOS获取APP的版本号和名称
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary]; CFShow(infoDictionary); // ap ...
- 外网访问VMware(Centos7.0,NAT模式)搭建的web服务器应用
首先参考 https://www.cnblogs.com/studyhard-cq/p/11551755.html 设置好NAT模式,能访问公网. 1.打开VMware,点击左上角编辑 ...
- Ubuntu Linux 查看、编辑、比较二进制文件
查看二进制有以下几种方法: 方法一:hexdump apt-get install libdata-hexdumper-perl 安装好之后就可以直接hexdump your_binary_file ...
- 记一次部署PHP遇到的编码问题故障
php开发给我项目和数据库,我按正常部署流程部署,开始发现之梦的后台登陆不了,后发现是属主属组不对,代码直接解压后是root的,更改后,后台能登陆,但部分显示乱码.后将正常的数据库文件重新导入后,显示 ...
- 单节点oracle、ASM 详细安装步骤
目录 1.安装环境 2.系统要求 2.1 Linux安装Oracle系统要求 1.查看RAM和交换空间以及磁盘大小 2.检查所需软件包 3.配置host和主机名 2.2修改操作系统核心参数 1.创建相 ...
- VMware:未能将管道连接到虚拟机, 所有的管道范例都在使用中
问题描述:虚拟机下的Ubuntu系统长时间死机无法正常关机,用Windows任务管理器关闭VMware也关不掉,没办法,只能直接关电脑了...重新打开电脑,启动VMware,发现提示客户机已经处于打开 ...
- vps 11步移站步骤笔记
移站是经常的事,现在把步骤写上,防止忘记命令 1.登录SSH 2.打包数据库,phpmyadmin中备份数据库,导入新数据库,数据库中域名链接进行相应替换 获取phpmyadmin root密码 ca ...
- jquery判断cookie是否存在
首先请加载jquery库与jquery cookie插件 http://code.jquery.com/jquery-latest.js http://files.cnblogs.com/afish/ ...
- STL源码阅读-traits与迭代器
迭代器模式 提供一种方法,使之能够依序访问容器的各个元素,而又无需暴露容器的内部表述方式 STL设计的中心思想在于将数据容器和算法分离开,容器和算法分开设计,迭代器则是两者之间的胶着剂,一般迭代器的设 ...