POJ1009:Edge Detection

来源:互联网 发布:摩尔定律失效 知乎 编辑:程序博客网 时间:2024/06/02 02:10

问题

描述
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、四周都有值位置情况1a1 = a = b = cd1 = d = x = ef1 = 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 = hd如果周围没有新点 那么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 = bd1 = d = xf1 = f = g结论  B(d) = B(x) 4、点位于上边d1 = d = x = ef1 = f = g = h结论  B(d) = B(x) 5、点位于下边a1 = a = b = cd1 = d = x = e结论  B(d) = B(x) 6、点在左上角x ef g第一个点肯定是新点 需要计算结论  B(x) 一定需要重新计算7、点在右上角d1 = d = xd1 = 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 = bd1 = d = x结论  B(d) = B(x) 综上述说需要计算的点的集合S ;S = {x|x是一个新点或新点周围的点}for x in S:    if x 是最右边的点:        S.add(x的下一个点,即下一列的起点)S.add(最后一列的起点)

验证案例

输入715 4100 1525 2175 225 5175 225 50 01035 500000000200 5000000000 03255 110 1255 210 1255 210 1255 10 00输出785 50 285 575 10150 275 30 2150 20 40 0100 499999990165 200 4999999900 03245 90 00

代码注意事项

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;}
原创粉丝点击