洪水充填C++

发布于 2024-12-18 19:31:01 字数 2240 浏览 3 评论 0原文

我在实施洪水填充时遇到问题。
任务是要求用户点击图像的白色部分(表示种子点),他想要用黑色填充。
该操作应该在二值图像上完成。
我正在使用 CImg 库。
无法使用递归算法。
我想出了一些办法,但它无法正常工作(间隙仅在种子点处变黑)。我对队列根本不熟悉,所以问题可能出在它们的实现上。

void floodfill(int x, int y, int c, int b, CImg <unsigned char>image)
{
    //c-black
    //b-white
    CImg<unsigned char> kopia(image.width(),image.height());

    for (int p=1; p<image.height()-1; p++)
    {
        for (int q=1; q<image.width()-1; q++)
        {
            kopia(p,q)=255; //setting kopia2 all white
        }
    }

    queue <pair<int,int> > a;
    int p;
    if(image(x, y) == c)
    {
        cout<<"Already black"<<endl;
        return;
    }
    else
    {
        a.push(make_pair(x, y));
        while(!a.empty())
        {
            a.pop();
            p=image(x+1, y);
            if((p == b) && (x < image.width()))
            {
                a.push(make_pair(x+1, y));
                kopia(x+1, y)=c;
                image(x+1, y)=c;
            }
            p = image(x-1, y);
            if((p == c) && (x > 0))
            {
                a.push(make_pair(x-1, y));
                kopia(x-1, y)=c;
                image(x-1, y)=c;
            }
            p=image(x, y+1);
            if((p == b) && (y < image.height()))
            {
                a.push(make_pair(x, y+1));
                kopia(x, y+1)=c;
                image(x, y+1)=c;
            }
            p=image(x, y-1);
            if((p == b) && (y > 0))
            {
                a.push(make_pair(x, y-1));
                kopia(x, y-1)=c;
                image(x, y-1)=c;
            }
        }
        saving(kopia);
    }
}

void hole (CImg <unsigned char>image)
{
    CImgDisplay image_disp(image,"Click a point");

    int c_x=0; //coordinates
    int c_y=0;

    while (!image_disp.is_closed())
    {
        image_disp.wait();
        if (image_disp.button())
        {
            c_x=image_disp.mouse_x();  //reads coordinates indicated by user
            c_y=image_disp.mouse_y();
        }
    }

    floodfill(c_x, c_y,0,255,image);
}

I have a problem with implementation of flood filling.
The task is to ask user to click on the white part of the image (indicating seed point), he want to fill with black.
The operation should be done on the binary images.
I'm using CImg library.
I can't use recursive algorithm.
I've came up with something but it is not working properly (the gap becomes black only in the seed point). I am not familiar with the queues at all, so maybe the problem is in their implementaion.

void floodfill(int x, int y, int c, int b, CImg <unsigned char>image)
{
    //c-black
    //b-white
    CImg<unsigned char> kopia(image.width(),image.height());

    for (int p=1; p<image.height()-1; p++)
    {
        for (int q=1; q<image.width()-1; q++)
        {
            kopia(p,q)=255; //setting kopia2 all white
        }
    }

    queue <pair<int,int> > a;
    int p;
    if(image(x, y) == c)
    {
        cout<<"Already black"<<endl;
        return;
    }
    else
    {
        a.push(make_pair(x, y));
        while(!a.empty())
        {
            a.pop();
            p=image(x+1, y);
            if((p == b) && (x < image.width()))
            {
                a.push(make_pair(x+1, y));
                kopia(x+1, y)=c;
                image(x+1, y)=c;
            }
            p = image(x-1, y);
            if((p == c) && (x > 0))
            {
                a.push(make_pair(x-1, y));
                kopia(x-1, y)=c;
                image(x-1, y)=c;
            }
            p=image(x, y+1);
            if((p == b) && (y < image.height()))
            {
                a.push(make_pair(x, y+1));
                kopia(x, y+1)=c;
                image(x, y+1)=c;
            }
            p=image(x, y-1);
            if((p == b) && (y > 0))
            {
                a.push(make_pair(x, y-1));
                kopia(x, y-1)=c;
                image(x, y-1)=c;
            }
        }
        saving(kopia);
    }
}

void hole (CImg <unsigned char>image)
{
    CImgDisplay image_disp(image,"Click a point");

    int c_x=0; //coordinates
    int c_y=0;

    while (!image_disp.is_closed())
    {
        image_disp.wait();
        if (image_disp.button())
        {
            c_x=image_disp.mouse_x();  //reads coordinates indicated by user
            c_y=image_disp.mouse_y();
        }
    }

    floodfill(c_x, c_y,0,255,image);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

残花月 2024-12-25 19:31:01

1)

    while(!a.empty())
    {
        x = a.front().first; //fixed as per ChristianRau's code
        y = a.front().second; //fixed as per ChristianRau's code
        a.pop();

你只是将当前的 x,y 坐标从堆栈中弹出,而没有查看它们是什么。

2)

        p = image(x-1, y);
        if((p == c) && (x > 0))

你的意思是检查它是否是白色的,就像你对其他方向所做的那样?

3)调用者传入黑白图像,如果图像的一部分是蓝色会发生什么?更好的方法是传递填充颜色(黑色),只要有白色,就用非黑色替换它。

1)

    while(!a.empty())
    {
        x = a.front().first; //fixed as per ChristianRau's code
        y = a.front().second; //fixed as per ChristianRau's code
        a.pop();

You just popped the current x,y coordinates off the stack without looking at what they were.

2)

        p = image(x-1, y);
        if((p == c) && (x > 0))

Did you mean to check if it was white, like you did with the other directions?

3) The caller passes in black and white, what happens if part of the image is blue? Better would be to pass in the filling color (black), and wherever you have white, replace that with not-black.

浪漫之都 2024-12-25 19:31:01

您是否意识到您始终使用相同的 xy 并且 a.pop() 不会返回任何事物? std::queue::pop 仅弹出队列的前端,但不返回它。您必须事先使用 std::queue::front 查询它。 添加

x = a.front().first;
y = a.front().second;

因此,只需在 while 循环内的 a.pop() 之前

即可。顺便说一句,您可能还想将 image(x, y) (也许还有 kopia(x, y))设置为 c在推送初始对之前,在 else 块的开头,尽管它也可能由其邻居的迭代设置。

Don't you realize that you are working with the same x and y all the time and that a.pop() doesn't return anything? std::queue::pop only pops the front of the queue, but doesn't return it. You have to query it beforehand using std::queue::front. So just add

x = a.front().first;
y = a.front().second;

right before a.pop() inside the while loop.

And by the way, you might also want to set image(x, y) (and maybe kopia(x, y)) to c at the beginning of the else block before pushing the initial pair, although it might also get set by its neighbours' iterations.

相守太难 2024-12-25 19:31:01

此外,CImg 中有一个内置函数可以完成您想要的操作:CImg::draw_fill()。

Also, there is a built-in function in CImg that does what you want : CImg::draw_fill().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文