zoukankan      html  css  js  c++  java
  • Edge Detection

     

    Edge Detection
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 22604   Accepted: 5311

    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 (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

    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. 

    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了几次,百思不得其解了好久……

      那就是最后一行的第一个格子,由于它没有下一行,所以它的像素值会发生变化

      有朋友问为什么最后一行的第一个格子需要考虑而别的行的第一个格子不需要考虑呢?

      首先,如果像这样像素值发生变化,自然会进行计算。

      其次,如果像素值没有发生变化,那无非就是担心换行之后,格子上方和下方的格子的数值变化,拿上方格子数值变化为例,如果两个格子(黄色)上方格子数值不一样,那紫色格子的数值发生变化时,必然会计算黄色格子的数值,所以此处不需计算。其他情况同理。

      而最下面一行的第一个格子,它的下面的格子不是数值发生变化,而是消失了,即可以理解为,它下面的格子数值发生了变化但是不会启动计算过程,所以最下面一行的第一个格子是特殊的。

      1 #include<iostream>
      2 #include<map>
      3 using namespace std;
      4 /*
      5 可以利用map<int,int>的first为下标,second为像素值
      6 一个输入map,一个输出map
      7 利用map的特性,输出map插入后自动以first排序
      8 输出的时候遍历输出map,如果second不同,则进行输出
      9 
     10 代码很乱包括了我的测试代码……
     11 */
     12 void Print(map<int,int> OutMap,int n,int Max)
     13 {
     14     long tempFirst = 0,tempSecond=0;
     15 /*
     16     map<int,int>::iterator iter = OutMap.begin();
     17     for(iter;iter != OutMap.end();iter++)
     18     {
     19         cout<<iter->first<<" "<<iter->second<<endl;
     20     }
     21 */
     22     map<int,int>::iterator iter1 = OutMap.begin();//向前迭代
     23     tempFirst = iter1->first;tempSecond = iter1->second;
     24     for(iter1;iter1 != OutMap.end();iter1++)
     25     {
     26         if(iter1->second != tempSecond)
     27         {
     28             cout<<tempSecond<<" "<<iter1->first-tempFirst<<endl;
     29 
     30             tempSecond = iter1->second;
     31             tempFirst = iter1->first;
     32         }
     33     }
     34     cout<<tempSecond<<" "<<Max-tempFirst<<endl;
     35 
     36     cout<<0<<" "<<0<<endl;
     37 }
     38 void Compute(map<int,int> In,int n,int Max)
     39 {//计算输出数组
     40     /**/
     41     map<int,int> OutMap;
     42     int Count=0;//记录数组下
     43     int temp=0;
     44     int arr[10] = {0,-n-1,-n,-n+1,-1,1,n-1,n,n+1,Max-n};
     45     ///对In进行遍历
     46     map<int,int>::iterator iter = In.begin();
     47     for(iter;iter != In.end();iter++)
     48     {
     49         for(int i=0;i<10;i++)
     50         {
     51             if(i == 9) Count = arr[i];
     52             else Count = iter->first + arr[i];//周围8个像素的下标,包括自己
     53             if(Count < 0 || Count >= Max)
     54             {//下标越界
     55                 continue;
     56             }
     57             else if(Count%n == n-1 && iter->first%n == 0 && n!=2&& n!=1)
     58             {//在最左边一列,没有左边像素
     59                 continue;
     60             }
     61             else if(Count%n == 0 && iter->first%n == n-1 && n!=2&& n!=1)
     62             {//在最右边一列,没有右边像素
     63                 continue;
     64             }
     65             else{
     66                 map<int,int>::iterator CountIter = In.begin();//指针定位到中心
     67                 CountIter = In.upper_bound(Count);
     68                 CountIter--;
     69                 //cout<<"测试CountIter:"<<CountIter->first<<" "<<CountIter->second<<endl;
     70                 ///计算当前像素的值
     71                 int Num = 0;
     72                 int tempNum = 0;
     73                 for(int j =1;j<9;j++)//考察周围的八个点
     74                 {
     75                     temp = Count + arr[j];
     76                     if(temp<0 || temp>=Max || temp%n==n-1&&Count%n==0&&n!=2 || temp%n==0&&Count%n==n-1&&n!=2)
     77                     {
     78                         continue;
     79                     }else{
     80                         map<int,int>::iterator tempIter;
     81                         tempIter = In.upper_bound(temp);//第一个大于temp的位置
     82                         //cout<<"测试tempIter:"<<tempIter->first<<" "<<tempIter->second<<endl;
     83                         tempIter--;
     84                         //cout<<"测试tempIter2:"<<tempIter->first<<" "<<tempIter->second<<endl;
     85                         tempNum = CountIter->second - tempIter->second;
     86                         if(tempNum < 0) tempNum = -1 * tempNum;
     87                     }
     88                     if(tempNum > Num) Num = tempNum;
     89                 }
     90                 ///插入到OutMap
     91                 OutMap.insert(pair<int,int>(Count,Num));
     92             }
     93         }
     94     }
     95     Print(OutMap,n,Max);
     96     OutMap.clear();
     97 }
     98 
     99 int main()
    100 {
    101     int n;
    102     map<int,int> InMap;
    103 
    104     cin>>n;
    105     cout<<n<<endl;
    106     while(n)
    107     {
    108 
    109         int num,len;
    110         long Count = 0;
    111         ///获取输入数组
    112         cin>>num>>len;
    113         while(len)
    114         {
    115             InMap.insert(pair<int,int>(Count,num));
    116             Count += len;//虚拟数组下标增加
    117             cin>>num>>len;
    118         }
    119         InMap.insert(pair<int,int>(1000000020,111));
    120 /*
    121         map<int,int>::iterator iter;//向前迭代
    122         for(iter = InMap.begin();iter != InMap.end();iter++)
    123         {
    124             cout<<iter->first<<","<<iter->second<<endl;
    125         }
    126 */
    127         ///输入结束,进行输出数组的计算
    128         Compute(InMap,n,Count);
    129         InMap.clear();
    130         cin>>n;
    131         cout<<n<<endl;
    132     }
    133 
    134 
    135     return 0;
    136 }
  • 相关阅读:
    03.部署 kubectl 命令行工具
    02.创建 CA 证书和秘钥
    01.组件版本和集群环境
    23.kubernetes 组件版本和配置策略
    22.Kubernetes Ingress: HTTP 7层路由机制
    Python程序中#-*-coding: UTF-8 -*-的作用
    Python程序中首行#!/usr/bin/env python的作用
    mac install php dev
    linux的nohup disown setsid screen
    linux 常用查找命令 小技巧
  • 原文地址:https://www.cnblogs.com/yxh-amysear/p/8287693.html
Copyright © 2011-2022 走看看