a working non-recursive floodfill algorithm written in C?

后端 未结 12 2219
日久生厌
日久生厌 2020-12-02 23:39

I\'ve been trying to find a working floodfill algorithm. Of the many algorithms I\'ve tried only the \'recursive line fill\' one behaves exactly as it should with the major

相关标签:
12条回答
  • 2020-12-03 00:12

    Here's some C++ code that does what you want. It uses a queue, and is more efficient about insertions into the queue.

    connectedRegion(const Point& source, RegionType& region, const Color target)
    {
        Color src_color = color_of(source, region);
        if (region.count(source) == 0 || src_color == target)
            return;
        std::queue<Point> analyze_queue;
        analyze_queue.push(source);
    
        while (!analyze_queue.empty())
        {
            if (color_of(analyze_queue.front()) != src_color)
            {
                analyze_queue.pop();
                continue;
            }
            Point leftmost_pt = analyze_queue.front();
                leftmost_pt.col -= 1;
            analyze_queue.pop();
            Point rightmost_pt = leftmost_pt;
                rightmost_pt.col += 2;
            while (color_of(leftmost_pt, region) == src_color)
                --leftmost_pt.col;
    
            while (color_of(rightmost_pt, region) == src_color)
                ++rightmost_pt.col;
    
            bool check_above = true;
            bool check_below = true;
                Point pt = leftmost_pt;
                ++pt.col;
            for (; pt.col < rightmost_pt.col; ++pt.col)
            {
                set_color(pt, region, target);
    
                Point pt_above = pt;
                        --pt_above.row;
                if (check_above)
                {
                    if (color_of(pt_above, region) == src_color)
                    {
                        analyze_queue.push(pt_above);
                        check_above = false;
                    }
                }
                else // !check_above
                {
                    check_above = (color_of(pt_above, region) != src_color);
                }
    
                Point pt_below = pt;
                        ++pt_below.row;
                if (check_below)
                {
                    if (color_of(pt_below, region) == src_color)
                    {
                        analyze_queue.push(pt_below);
                        check_below = false;
                    }
                }
                else // !check_below
                {
                    check_below = (color_of(pt_below, region) != src_color);
                }
            } // for 
        } // while queue not empty
        return connected;
    }
    
    0 讨论(0)
  • 2020-12-03 00:12

    Isn't there a proof somewhere that all recursive functions can be implemented as an iterative function by using local data to mimic a stack? You could probably use std::vector to create stack-like behavior of the algorithm without blowing the stack since it will use the heap.

    EDIT: I noticed you are using C, so instead of std::vector, you could just implement similar behavior via realloc as you need to add more elements to your local "stack" of whatever data structure you would use.

    0 讨论(0)
  • 2020-12-03 00:13

    A quick googling brings up the Wikipedia article on Flood Fill which includes pseudocode implementations which are not recursive. Below is some code that could help get you started, a basic queue implementation in C:

    typedef struct queue_ { struct queue_ *next; } queue_t;
    typedef struct ffnode_ { queue_t node; int x, y; } ffnode_t;
    
    /* returns the new head of the queue after adding node to the queue */
    queue_t* enqueue(queue_t *queue, queue_t *node) {
        if (node) {
            node->next = queue;
            return node;
        }
        return NULL;
    }
    
    /* returns the head of the queue and modifies queue to be the new head */
    queue_t* dequeue(queue_t **queue) {
        if (queue) {
            queue_t *node = (*queue);
            (*queue) = node->next;
            node->next = NULL;
            return node;
        }
        return NULL;
    }
    
    ffnode_t* new_ffnode(int x, int y) {
        ffnode_t *node = (ffnode_t*)malloc(sizeof(ffnode_t));
        node->x = x; node->y = y;
        node->node.next = NULL;
        return node;
    }
    
    void flood_fill(image_t *image, int startx, int starty, 
                    color_t target, color_t replacement) {
        queue_t *head = NULL;
        ffnode_t *node = NULL;
    
        if (!is_color(image, startx, starty, target)) return;
    
        node = new_ffnode(startx, starty);
        for ( ; node != NULL; node = (ffnode_t*)dequeue(&head)) {
            if (is_color(image, node->x, node->y, target)) {
                ffnode_t *west = node, *east = node;
    
                recolor(image, node->x, node->y, replacement);
                /* 1. move w to the west until the color of the node to the west
                   no longer matches target */
                ...
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-03 00:13

    You can convert any recursive algorithm to iterative by creating an explicit stack or queue and loading work onto it/pulling it off.

    All you need is to choose a nice, compact representation of the work to be done. Worst case: create a struct holding the arguments you would normally pass to the recursive version...

    0 讨论(0)
  • 2020-12-03 00:16

    I have a non-recursive flood fill, but I won't post it because it's the solution to a homework assignment. But here's a hint: depth-first search, which is the natural algorithm, uses far more auxiliary space than a breadth-first search. Here's what I wrote at the time (suitably expurgated):

    I dare not try depth-first search by simple recursion; the depth of recursion is limited only by REDACTED, and my experiments show that an PROBLEM REDACTED could nevertheless require a stack depth of over a million. So I put the stack in an auxiliary data structure. Using an explicit stack actually makes it easy to try breadth-first search as well, and it turns out that breadth-first search can use forty times less space than depth-first search.

    For my data structure I used the Seq_T from Dave Hanson's C Interfaces and Implementations; changing from depth-first to breadth-first requires changing just one function call.

    0 讨论(0)
  • 2020-12-03 00:23

    Here is a guide for a non-recursive routine which completes 10 million pixels per second: it's called marching-floodfills, what happens if you march the previously recursive routine forwards in a X-Y loop.

    write your own memory, a 2D array to record verified spaces, and another array which records the complete filled image, and read and write to them using this loop system... it averages 20 instructions per pixel. i dealt with 2 billion voxel graphs at 5 million Voxels per second using above video logic.

    0 讨论(0)
提交回复
热议问题