POJ1009:Edge Detection

问题

描述
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 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 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.

问题描述的很清楚, 就是把点A(i, j)转化为B(i, j)
转化规则就是 B(i, j) = max{ A(i, j) - A’(i’,j’)| A’ 是A周围的8个点}

解决方案

根据题意,最多1000对数据( 数值,长度), 但长度Images contain 2 to 1,000,000,000 (109) pixels。 所以如果暴力计算,每个点计算一次肯定超时。在网上查找方案 最多的就是跳跃式编程,计算每个新的点(有1000个点)以及其周围的8个点,最多9000个点。 其它点的值=前一个点的值。 这样就能解决此问题。当然还有一些异常的点需要处理

这里有个问题, 为什么这么做? 以及哪些是异常点? 下面给出证明,看看除了新点以及新点周围的点外 其它点的值是否和它前面的值相等? 如果不相等 那就是异常点,也需要重新计算。

假定 x 周围不是新点。 根据点的位置可以划分如下9类

1、四周都有值
位置情况1
a1 = a = b = c
d1 = d = x = e
f1 = f = g = h

位置情况2
最左边               最右边
                    a1=(a)
a = b = c           d1=(d)
d = x = e           f1=(f)
f = g = h

结论 B(d) = B(x) 

2、点位于左边
最左边             最右边
                a1 a=(b)
b = c           d1 d=(x)
x = e           f1 f=(g)
g = h

d如果周围没有新点 那么a1=a  d1=d f1=f ⇒ B(d) = B(x)
    否则 B(d) 受a1 d1 f1 a f的影响  B(x)受c e h b g的影响  
        虽然a=b=c f=g=h 但如果a1!=a  d1!=d f1!=f 
        B(d) 有可能不等于 B(x)
结论  当d重新计算时 x也要重新计算; 否则B(d) = B(x) 

3、点位于右边
a1 = a = b
d1 = d = x
f1 = f = g
结论  B(d) = B(x) 

4、点位于上边
d1 = d = x = e
f1 = f = g = h
结论  B(d) = B(x) 

5、点位于下边
a1 = a = b = c
d1 = d = x = e
结论  B(d) = B(x) 

6、点在左上角
x e
f g
第一个点肯定是新点 需要计算
结论  B(x) 一定需要重新计算

7、点在右上角
d1 = d = x
d1 = f = g
结论  B(d) = B(x) 

8、点在左下角
最左边         最右边
            a1 a=(b)
b = c       d1 d=(x)
x = e       f1 f=(g)

d周围没有新点时 
B(d) 受a1 d1 f1 a(b) f的影响  B(x)受c=b(a) 的影响 
d不是新点 a1=a=b  但还要考虑d1=d对d的影响 B(d)都有可能不等于B(x)
d是新点 B(d)都有可能不等于B(x)
结论  B(x) 一定需要重新计算

9、点在右下角
a1 = a = b
d1 = d = x
结论  B(d) = B(x) 


综上述说
需要计算的点的集合S ;
S = {x|x是一个新点或新点周围的点}
for x in S:
    if x 是最右边的点:
        S.add(x的下一个点,即下一列的起点)
S.add(最后一列的起点)

验证案例

输入
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

输出
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

代码注意事项

1、最多需要继续多少个点 
新点N1000 
一个新点最多影响8个点, 假定这9个点中有三个点在最右侧, 按照上面讨论的第二种情况,最多又回影响最左侧的3个点。 所以不会超过(1+8+3)N12N个点

2、给每一个点编号id
对应的坐标是(id/width, id%width)

代码实现


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* 最多1000对 */
#define N 1000

/* 最多需要计算像素的个数 */
#define NN (12*N+1)

/*
A, Len 存储input
*/
int A[N], Len[N], n;

/*
存储答案 最多NN个点
*/
int ans[NN][2], nn;


/*
 hash table 存储需要计算的点
 */
int ids[NN];
int setId(int id)
{
    int i, n = NN;
    int hashId = id % n;
    i = hashId;
    while(ids[i]!=-1 && ids[i]!=id && i != hashId-1) i = (i+1)%n;
    if( i==hashId-1 ){ ((void(*)())0)() ;}
    if(ids[i] == -1){
        ids[i] = id;
    }
    return i;
}

/*
根据二分查找思想 计算编号[0,n) 返回对应的值的下标
eg:编号id的值=A[bSearch(id)]
*/
int idLen[N];
int bSearch(int id)
{
     int i,j,v;
     i=0; j=n-1;
     while(i<j)
     {
        v = (i+j)/2;
        if( id <= idLen[v] )j=v;
        else i = v+1;
     }
     return i;
}

int main()
{
     int width, num;
     int i,j,ii,jj,k,u,v,id,newid,maxV;  //k,u,v,s,q,a,b,c,l,;
     int a,b,c;
     int iUp,iDown,jLeft,jRigth;
     while( scanf("%d", &width)==1 && width )
     {
        n=nn=num=0;
        memset(ids, -1,sizeof(ids));
        while ( scanf("%d %d", &A[n], &Len[n])==2 && (A[n] || Len[n]) )
        {
            num += Len[n];
            idLen[n] = num-1;
            n++;
        }

        iUp=0;  iDown=num/width - 1;
        jLeft=0;jRigth=width-1;

        id = 0;
        for(k=0; k<n; k++)
        {
            i = id/width;
            j = id%width;
            for(u=-1;u<=1;u++)
            for(v=-1;v<=1;v++)
            {
                ii = i+u; jj = j+v;
                if ( ii<iUp || ii>iDown || jj<jLeft || jj>jRigth ) continue;
                newid = ii*width+jj;
                setId(newid);
                if( jj == jRigth && newid+1<num )
                {
                    setId(newid+1);
                }
            }
            id += Len[k];
        }
        setId(iDown*width);

        // sort
        for(k=0; k<NN; k++) if(ids[k]!=-1)
        {
            id = ids[k];
            i = id/width;
            j = id%width;
            a = A[bSearch(id)];

            maxV = 0;
            for(u=-1;u<=1;u++)
            for(v=-1;v<=1;v++)
            {
                ii = i+u;
                jj = j+v;
                if ( ii<iUp || ii>iDown || jj<jLeft || jj>jRigth || (i==ii&&j==jj) ) continue;
                newid = ii*width+jj;

                b=A[bSearch(newid)];
                c = a-b;
                if( c > maxV ) maxV = c;
                else if ( -c > maxV ) maxV = -c;
            }
            // insert ans
            u=nn-1;
            while(u>=0 && ans[u][0] > id) {
                ans[u+1][0]=ans[u][0];
                ans[u+1][1]=ans[u][1];
                u--;
            };
            ans[u+1][0]=id;
            ans[u+1][1]=maxV;
            nn++;
        }

        //print ans
        if(ans[nn-1][0]!=num-1){ ans[nn][0]=num-1; ans[nn][1]=ans[nn-1][1]; nn++;}

        printf("%d\n", width);
        i = ans[0][0];
        v = ans[0][1];
        for(k=1;k<=nn;k++)
        {
            while( k<nn && ans[k-1][1]==ans[k][1] ) k++;
            if(k==nn)
            {
                printf("%d %d\n", v, ans[k-1][0] - i + 1);
                break;
            }
            else if(k<nn)
            {
                printf("%d %d\n", v, ans[k][0] - i);
                i = ans[k][0];
                v = ans[k][1];
            }
        }
        printf("0 0\n");
     }
     printf("0");
     return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值