White spaces left in coloring using QueueLinearFloodFillAlgorithm

China☆狼群 提交于 2019-12-06 04:38:55

The white/grey pixels are a result of anti-aliasing, which is used to smooth the edges of the lines. To avoid these artifacts, you could simply not use anti-aliasing when creating the images, or else you could use a two-step tolerance: a lower tolerance value for propagating the flood fill, and a higher one for coloring the pixels but not propagating the fill any further.

However both of these approaches will destroy the anti-aliasing in the image, which will reduce image quality. Another approach is to do another pass over the image and process the pixels bordering the fill (those where pixelsChecked is false but there is at least one neighbour where pixelsChecked is true) and compute an anti-aliased pixel value, assuming that the pixels are being anti-aliased against a black line.

public boolean isFilled(int x, int y)
{
    if((x < 0) || (y < 0) || (x >= width) || (y >= height))
        return false;
    return pixelsChecked[(width * y) + x];
}

public boolean isNeighbourFilled(int x, int y)
{
    // return true if at least one neighbour is filled:
    for(int offsetY = -1; offsetY <= 1; offsetY++)
    {
        for(int offsetX = -1; offsetX <= 1; offsetX++)
        {
            if((offsetX != 0) && (offsetY != 0) &&
                isFilled(x + offsetX, y + offsetY))
                return true;
        }
    }
    return false;
}

public void antiAliasFillOutline()
{
    for(int y = 0; y < height; y++)
    {
        for(int x = 0; x < width; x++)
        {
            // if pixel is not filled by neighbour is then it's on the border
            if(!isFilled(x, y) && isNeighbourFilled(x, y))
            {
                // compute an anti-aliased pixel value:
                antiAliasPixel(x, y);
            }
        }
    }
}

public void antiAliasPixel(int x, int y)
{
    int pixel = pixels[(width * y) + x];
    int red = (pixel >>> 16) & 0xff;
    int green = (pixel >>> 8) & 0xff;
    int blue = pixel & 0xff;

    int fillred = (fillColor >>> 16) & 0xff;
    int fillgreen = (fillColor >>> 8) & 0xff;
    int fillblue = fillColor & 0xff;

    // work out how much to anti-alias from 0 to 256:
    int amount = ((red + green + blue) * 256) / 
        (startColor[0] + startColor[1] + startColor[2]);
    if(amount > 256)
        amount = 256;

    red = (fillred * amount) >> 8;
    green = (fillgreen * amount) >> 8;
    blue = (fillblue * amount) >> 8;

    pixels[(width * y) + x] = 0xff000000 | (red << 16) | (green << 8) | blue;
}

Call antiAliasFillOutline() at the end of the flood fill.

You could speed it up a bit (at the expense of readability) by inlining some of the function calls and removing the bounds checks on pixelsChecked:

public void antiAliasFillOutlineFaster()
{
    for(int y = 1; y < height - 1; y++)
    {
        int i = (y * width) + 1;
        for(int x = 1; x < width - 1; x++)
        {
            // if pixel is not filled by neighbour is then it's on the border
            if(!pixelsChecked[i] && 
                (pixelsChecked[i-1] || pixelsChecked[i+1] ||
                 pixelsChecked[i-width-1] || pixelsChecked[i-width] || pixelsChecked[i-width+1] ||
                 pixelsChecked[i+width-1] || pixelsChecked[i+width] || pixelsChecked[i+width+1]))
            {
                // compute an anti-aliased pixel value:
                antiAliasPixel(x, y);
            }
            i++;
        }
    }
}

You could also try just checking the 4 neighbouring pixels instead of the 8 neighbours including diagonals. Also, values like fillred etc and (startColor[0] + startColor[1] + startColor[2]) could be computed once and stored in member variables.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!