A simple implementation of the manshui Filling Algorithm (Qt), the algorithm qt

Source: Internet
Author: User

A simple implementation of the manshui Filling Algorithm (Qt), the algorithm qt

The so-called manshui filling algorithm is an algorithm that gives a point in a China Unicom domain and uses this as a starting point to locate all the other points in the China Unicom domain and fill it with a specified color.
It is called manshui filling because this Algorithm simulates the process of rising water. From one point on, the water flow gradually increases until it passes through all areas.
For more information about this algorithm, see the following link.
Https://en.wikipedia.org/wiki/Flood_fill

This algorithm is very useful when we look for a specific area. Therefore, it took me some time to write a program. The algorithm I implemented is similar to the method in the following figure, but I fill a row each time.

The following floodFill_Gray function is used to fill the grayscale image. The grayscale filling of a Unicom domain is newVal.

static inline bool fillPoint_Gray( QImage &image, QPoint p, uchar val, uchar newVal, QStack<QPoint> &stack){    int x = p.rx();    int y = p.ry();    uchar *line = image.scanLine(y);    if( line[x] != val )    {        return false;    }    line[x] = newVal;    if( y > 0 )    {        uchar *last = image.scanLine(y - 1);        if( last[x] == val )        {            stack.push(QPoint(x, y - 1));        }    }    if( y < image.height() - 1 )    {        uchar *next = image.scanLine(y + 1);        if( next[x] == val )        {            stack.push(QPoint(x, y + 1));        }    }    return true;}bool floodFill_Gray(QImage &image, QPoint seedPoint, uchar newVal ){    if(image.format() != QImage::Format_Indexed8)    {        return false;    }    int width = image.width();    int height = image.height();    int x = seedPoint.rx();    int y = seedPoint.ry();    if(x < 0 || x >= width || y < 0 || y >= height)    {        return false;    }    int value = image.scanLine(y)[x];    QStack<QPoint> stack;    stack.push(seedPoint);    while(!stack.isEmpty())    {        QPoint p = stack.pop();        bool ret = fillPoint_Gray(image, p, value, newVal, stack);        bool ret2 = ret;        y = p.ry();        x = p.rx();        x--;        while(x >= 0 && ret)        {            ret = fillPoint_Gray(image, QPoint(x, y), value, newVal, stack);            x--;        }        x = p.rx();        x ++;        while(x < width && ret2)        {            ret2 = fillPoint_Gray(image, QPoint(x, y), value, newVal, stack);            x++;        }    }    return true;}

Sometimes, due to noise and other effects, the original colors in the areas to be filled are not exactly the same. Fuzzy filling can be used in this case. The so-called fuzzy fill is to set a color range, the points within the color range are considered as the interior point of the area.
The following code implements this function.

static inline bool fillPoint_Gray( QImage &image, QPoint p, uchar low, uchar high, uchar newVal, QStack<QPoint> &stack){    int x = p.rx();    int y = p.ry();    uchar *line = image.scanLine(y);    if( line[x] < low || line[x] > high )    {        return false;    }    line[x] = newVal;    if( y > 0 )    {        uchar *last = image.scanLine(y - 1);        if( last[x] >= low && last[x] <= high )        {            stack.push(QPoint(x, y - 1));        }    }    if( y < image.height() - 1 )    {        uchar *next = image.scanLine(y + 1);        if( next[x] >= low && next[x] <= high )        {            stack.push(QPoint(x, y + 1));        }    }    return true;}bool floodFill_Gray(QImage &image, QPoint seedPoint, int low, int high, uchar newVal ){    if(image.format() != QImage::Format_Indexed8)    {        return false;    }    low = qBound(0, low, 255);    high = qBound(0, high, 255);    if(low > high)    {        return false;    }    QStack<QPoint> stack;    stack.push(seedPoint);    int width = image.width();    while(!stack.isEmpty())    {        QPoint p = stack.pop();        bool ret = fillPoint_Gray(image, p, low, high, newVal, stack);        bool ret2 = ret;        int y = p.ry();        int x = p.rx();        x--;        while(x >= 0 && ret)        {            ret = fillPoint_Gray(image, QPoint(x, y), low, high, newVal, stack);            x--;        }        x = p.rx();        x ++;        while(x < width && ret2)        {            ret2 = fillPoint_Gray(image, QPoint(x, y), low, high, newVal, stack);            x++;        }    }    return true;}

I also wrote a color image for filling. This code is relatively simple, and fuzzy color identification has not yet been implemented. It is not easy to measure the distance between two color values in the RGB color space. If we simply use Euclidean distance, we may feel a little different from our eyes. We may think that the distance between the two colors is not far away, and the two colors that seem to be similar may be quite large.

static inline bool fillPoint_RGB32( QImage &image, QPoint p, QRgb val, QRgb newVal, QStack<QPoint> &stack){    int x = p.rx();    int y = p.ry();    QRgb *line = (QRgb*)image.scanLine(y);    if( line[x] != val )    {        return false;    }    line[x] = newVal;    if( y > 0 )    {        QRgb *last = (QRgb*)image.scanLine(y - 1);        if( last[x] == val )        {            stack.push(QPoint(x, y - 1));        }    }    if( y < image.height() - 1 )    {        QRgb *next = (QRgb*)image.scanLine(y + 1);        if( next[x] == val )        {            stack.push(QPoint(x, y + 1));        }    }    return true;}bool floodFill_RGB32(QImage &image, QPoint seedPoint, QRgb newVal ){    qDebug() << image.format();    if(image.format() != QImage::Format_RGBA8888 && image.format() != QImage::Format_ARGB32 )    {        return false;    }    int width = image.width();    int height = image.height();    int x = seedPoint.rx();    int y = seedPoint.ry();    if(x < 0 || x >= width || y < 0 || y >= height)    {        return false;    }    QRgb value = image.pixel(x, y);    QStack<QPoint> stack;    stack.push(seedPoint);    while(!stack.isEmpty())    {        QPoint p = stack.pop();        bool ret = fillPoint_RGB32(image, p, value, newVal, stack);        bool ret2 = ret;        y = p.ry();        x = p.rx();        x--;        while(x >= 0 && ret)        {            ret = fillPoint_RGB32(image, QPoint(x, y), value, newVal, stack);            x--;        }        x = p.rx();        x ++;        while(x < width && ret2)        {            ret2 = fillPoint_RGB32(image, QPoint(x, y), value, newVal, stack);            x++;        }    }    return true;}

Below is a test image.

I want to fill the largest Red China Unicom area in blue. The following is the result after filling.

However, this algorithm has a note that it only treats the adjacent pixels on the top, bottom, and left as the same, and the adjacent pixels on the diagonal lines as not connected. The reason for this design is to deal with the following situation. If we think it is a combination, all the White areas will be connected, which is different from our intuitive feeling.

Of course, after such processing, two isolated points in the black area will be considered by the program not to be connected with other black areas. This is also different from our intuitive feeling. In short, the two situations cannot be both considered.

Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.