c - 高效的 8 连接洪水填充

标签 c algorithm graphics flood-fill

我一直在使用 Paul Heckbert 的优秀种子填充算法(可用 here 和书 Graphic Gems (1990))。

算法可能看起来很复杂。它构思周到,而且速度很快!不幸的是,它仅适用于 4 连通空间。

我正在为 8 个连通空间(沿对角线泄漏)寻找一种设计良好的快速算法。有什么想法吗?

就此问题而言,递归访问或重复将每个单元格放入堆栈不会被视为设计良好。伪代码中可用的算法最受欢迎(Heckbert 的代码和伪代码均可用)。

谢谢!

为了完整起见,这里复制了 Heckbert 的算法:

/*
 * A Seed Fill Algorithm
 * by Paul Heckbert
 * from "Graphics Gems", Academic Press, 1990
 *
 * user provides pixelread() and pixelwrite() routines
 */

/*
 * fill.c : simple seed fill program
 * Calls pixelread() to read pixels, pixelwrite() to write pixels.
 *
 * Paul Heckbert    13 Sept 1982, 28 Jan 1987
 */

typedef struct {        /* window: a discrete 2-D rectangle */
    int x0, y0;         /* xmin and ymin */
    int x1, y1;         /* xmax and ymax (inclusive) */
} Window;

typedef int Pixel;      /* 1-channel frame buffer assumed */

Pixel pixelread();

typedef struct {short y, xl, xr, dy;} Segment;
/*
 * Filled horizontal segment of scanline y for xl<=x<=xr.
 * Parent segment was on line y-dy.  dy=1 or -1
 */

#define MAX 10000       /* max depth of stack */

#define PUSH(Y, XL, XR, DY) /* push new segment on stack */ \
    if (sp<stack+MAX && Y+(DY)>=win->y0 && Y+(DY)<=win->y1) \
    {sp->y = Y; sp->xl = XL; sp->xr = XR; sp->dy = DY; sp++;}

#define POP(Y, XL, XR, DY)  /* pop segment off stack */ \
    {sp--; Y = sp->y+(DY = sp->dy); XL = sp->xl; XR = sp->xr;}

/*
 * fill: set the pixel at (x,y) and all of its 4-connected neighbors
 * with the same pixel value to the new pixel value nv.
 * A 4-connected neighbor is a pixel above, below, left, or right of a pixel.
 */

fill(x, y, win, nv)
int x, y;   /* seed point */
Window *win;    /* screen window */
Pixel nv;   /* new pixel value */
{
    int l, x1, x2, dy;
    Pixel ov;   /* old pixel value */
    Segment stack[MAX], *sp = stack;    /* stack of filled segments */

    ov = pixelread(x, y);       /* read pv at seed point */
    if (ov==nv || x<win->x0 || x>win->x1 || y<win->y0 || y>win->y1) return;
    PUSH(y, x, x, 1);           /* needed in some cases */
    PUSH(y+1, x, x, -1);        /* seed segment (popped 1st) */

    while (sp>stack) {
    /* pop segment off stack and fill a neighboring scan line */
    POP(y, x1, x2, dy);
    /*
     * segment of scan line y-dy for x1<=x<=x2 was previously filled,
     * now explore adjacent pixels in scan line y
     */
    for (x=x1; x>=win->x0 && pixelread(x, y)==ov; x--)
        pixelwrite(x, y, nv);
    if (x>=x1) goto skip;
    l = x+1;
    if (l<x1) PUSH(y, l, x1-1, -dy);        /* leak on left? */
    x = x1+1;
    do {
        for (; x<=win->x1 && pixelread(x, y)==ov; x++)
        pixelwrite(x, y, nv);
        PUSH(y, l, x-1, dy);
        if (x>x2+1) PUSH(y, x2+1, x-1, -dy);    /* leak on right? */
skip:       for (x++; x<=x2 && pixelread(x, y)!=ov; x++);
        l = x;
    } while (x<=x2);
    }
}

最佳答案

检查 cvFloodFill()来自 OpenCV框架。 flags 参数似乎是用来设置这个值的:

void cvFloodFill(CvArr* image, 
                 CvPoint seed_point, 
                 CvScalar new_val, 
                 CvScalar lo_diff=cvScalarAll(0), 
                 CvScalar up_diff=cvScalarAll(0), 
                 CvConnectedComp* comp=NULL, 
                 int flags=4, 
                 CvArr* mask=NULL)

关于c - 高效的 8 连接洪水填充,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9609038/

相关文章:

c - 如何判断 FILE* 是否引用一个目录?

c - 为什么指针变量在释放后会存储其先前存储的地址的新地址?

无法打开输出文件 name.exe 权限在 Eclipse C/C++ 中被拒绝

Swift Mini-Max Sum 一个测试用例失败 - HackerRank

android - 在 Android TextView 中显示进度

c - void/void * 声明行为

algorithm - 成员选择期间 "get best match"的 IntelliSense 规则

algorithm - 树的深度和直径有什么区别?

c++ - 写入 BMP 数据变得垃圾

ios - Metal :我需要多个RenderPipelines才能具有多个着色器吗?