Flood filling algorithm doesn't work as expected - it creates gaps between pixels
Well, I can't be so expressive in the title, so I will try to explain it here.
Basically my flood filling algorithm is doing this:
The different colors means the following:
- Blue pixels are the points from the polygon
- Red pixels are what Flood Fill has already filled
- Magenta is the combination of both colors
- Yellow pixels should never appear (that means that the algorithm that iterates the shape has already been iterated)
- Everything else is the source texture
This is my current method:
/// <summary>
/// Floods the fill.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source">The source.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="target">The target.</param>
/// <param name="replacement">The replacement.</param>
public static void FloodFill<T>(this T source, int x, int y, int width, int height, T target, T replacement)
where T : IEquatable<T>
int i;
source.FloodFill(x, y, width, height, target, replacement, out i);
/// <summary>
/// Floods the array following Flood Fill algorithm
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source">The source.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="target">The target to replace.</param>
/// <param name="replacement">The replacement.</param>
/// <param name="i">The i.</param>
// This was generic
public static void FloodFill<T>(this T source, int x, int y, int width, int height, T target, T replacement, out int i)
where T : IEquatable<T>
i = 0;
HashSet<int> queue = new HashSet<int>();
queue.Add(P(x, y, width, height));
while (queue.Count > 0)
int _i = queue.First(),
_x = _i % width,
_y = _i / width;
queue.Remove(_i);
if (source[_i].Equals(target))
source[_i] = replacement;
for (int offsetX = -1; offsetX < 2; offsetX++)
for (int offsetY = -1; offsetY < 2; offsetY++)
if (i > 100000)
break;
I can't show the other code, but I can try to explain it.
Basically, we have this texture (https://themindheist.files.wordpress.com/2015/03/gta_usa_map3.png) (It's too big to be here).
- We iterate it pixel by pixel.
- If we found any allowed pixel (Grass, Rock, Ice, Snow or whatever) then...
- We start looking for the shape of the current biome
- Then before continuing iterating we call Flood Fill algorithm.
- With this call we ensure that we will never pass over any pixel that form part of any of the map's polygons.
But as you can see, I have problems.
Watching at my implementation I suppose that when enqueued pixels looks for neighbors they are trapped and they don't return any neighbor pixel.
Or maybe, this is the way my flood fill algorithm executes (under special conditions I don't know).
What could you suggest/recommend me to do?
Note: The texture was get when I manually exited the method. So, my fill algorithm is filling the texture by "layers" that's why there are so many yellow pixels.
c# algorithm unity3d optimization flood-fill
|
show 4 more comments
Well, I can't be so expressive in the title, so I will try to explain it here.
Basically my flood filling algorithm is doing this:
The different colors means the following:
- Blue pixels are the points from the polygon
- Red pixels are what Flood Fill has already filled
- Magenta is the combination of both colors
- Yellow pixels should never appear (that means that the algorithm that iterates the shape has already been iterated)
- Everything else is the source texture
This is my current method:
/// <summary>
/// Floods the fill.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source">The source.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="target">The target.</param>
/// <param name="replacement">The replacement.</param>
public static void FloodFill<T>(this T source, int x, int y, int width, int height, T target, T replacement)
where T : IEquatable<T>
int i;
source.FloodFill(x, y, width, height, target, replacement, out i);
/// <summary>
/// Floods the array following Flood Fill algorithm
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source">The source.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="target">The target to replace.</param>
/// <param name="replacement">The replacement.</param>
/// <param name="i">The i.</param>
// This was generic
public static void FloodFill<T>(this T source, int x, int y, int width, int height, T target, T replacement, out int i)
where T : IEquatable<T>
i = 0;
HashSet<int> queue = new HashSet<int>();
queue.Add(P(x, y, width, height));
while (queue.Count > 0)
int _i = queue.First(),
_x = _i % width,
_y = _i / width;
queue.Remove(_i);
if (source[_i].Equals(target))
source[_i] = replacement;
for (int offsetX = -1; offsetX < 2; offsetX++)
for (int offsetY = -1; offsetY < 2; offsetY++)
if (i > 100000)
break;
I can't show the other code, but I can try to explain it.
Basically, we have this texture (https://themindheist.files.wordpress.com/2015/03/gta_usa_map3.png) (It's too big to be here).
- We iterate it pixel by pixel.
- If we found any allowed pixel (Grass, Rock, Ice, Snow or whatever) then...
- We start looking for the shape of the current biome
- Then before continuing iterating we call Flood Fill algorithm.
- With this call we ensure that we will never pass over any pixel that form part of any of the map's polygons.
But as you can see, I have problems.
Watching at my implementation I suppose that when enqueued pixels looks for neighbors they are trapped and they don't return any neighbor pixel.
Or maybe, this is the way my flood fill algorithm executes (under special conditions I don't know).
What could you suggest/recommend me to do?
Note: The texture was get when I manually exited the method. So, my fill algorithm is filling the texture by "layers" that's why there are so many yellow pixels.
c# algorithm unity3d optimization flood-fill
You are missing marking pixels as visited. At the moment you can visit a node multiple times
– juvian
Nov 14 '18 at 20:12
I mark pixels as visited outside of the Flood Fill algorithm, and I suppose I do the same when I check!queue.Contains(targetIndex)
. In this case, what do you mean?
– z3nth10n
Nov 14 '18 at 20:18
1
You start with source. On the first step you remove it from the queue add its neighbour's to the queue. Now you remove first neighbor added from the queue and you will add source again to the queue because it is not in it anymore
– juvian
Nov 14 '18 at 20:22
So, it's better to do thisqueue.Remove(_i)
at the end or what do you suggest me?
– z3nth10n
Nov 14 '18 at 20:40
I created another forked fiddle: dotnetfiddle.net/jIhRSU and I see no differences, so I will check this. Also, I'm testing if I really need to check for Interloecked.
– z3nth10n
Nov 14 '18 at 20:41
|
show 4 more comments
Well, I can't be so expressive in the title, so I will try to explain it here.
Basically my flood filling algorithm is doing this:
The different colors means the following:
- Blue pixels are the points from the polygon
- Red pixels are what Flood Fill has already filled
- Magenta is the combination of both colors
- Yellow pixels should never appear (that means that the algorithm that iterates the shape has already been iterated)
- Everything else is the source texture
This is my current method:
/// <summary>
/// Floods the fill.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source">The source.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="target">The target.</param>
/// <param name="replacement">The replacement.</param>
public static void FloodFill<T>(this T source, int x, int y, int width, int height, T target, T replacement)
where T : IEquatable<T>
int i;
source.FloodFill(x, y, width, height, target, replacement, out i);
/// <summary>
/// Floods the array following Flood Fill algorithm
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source">The source.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="target">The target to replace.</param>
/// <param name="replacement">The replacement.</param>
/// <param name="i">The i.</param>
// This was generic
public static void FloodFill<T>(this T source, int x, int y, int width, int height, T target, T replacement, out int i)
where T : IEquatable<T>
i = 0;
HashSet<int> queue = new HashSet<int>();
queue.Add(P(x, y, width, height));
while (queue.Count > 0)
int _i = queue.First(),
_x = _i % width,
_y = _i / width;
queue.Remove(_i);
if (source[_i].Equals(target))
source[_i] = replacement;
for (int offsetX = -1; offsetX < 2; offsetX++)
for (int offsetY = -1; offsetY < 2; offsetY++)
if (i > 100000)
break;
I can't show the other code, but I can try to explain it.
Basically, we have this texture (https://themindheist.files.wordpress.com/2015/03/gta_usa_map3.png) (It's too big to be here).
- We iterate it pixel by pixel.
- If we found any allowed pixel (Grass, Rock, Ice, Snow or whatever) then...
- We start looking for the shape of the current biome
- Then before continuing iterating we call Flood Fill algorithm.
- With this call we ensure that we will never pass over any pixel that form part of any of the map's polygons.
But as you can see, I have problems.
Watching at my implementation I suppose that when enqueued pixels looks for neighbors they are trapped and they don't return any neighbor pixel.
Or maybe, this is the way my flood fill algorithm executes (under special conditions I don't know).
What could you suggest/recommend me to do?
Note: The texture was get when I manually exited the method. So, my fill algorithm is filling the texture by "layers" that's why there are so many yellow pixels.
c# algorithm unity3d optimization flood-fill
Well, I can't be so expressive in the title, so I will try to explain it here.
Basically my flood filling algorithm is doing this:
The different colors means the following:
- Blue pixels are the points from the polygon
- Red pixels are what Flood Fill has already filled
- Magenta is the combination of both colors
- Yellow pixels should never appear (that means that the algorithm that iterates the shape has already been iterated)
- Everything else is the source texture
This is my current method:
/// <summary>
/// Floods the fill.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source">The source.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="target">The target.</param>
/// <param name="replacement">The replacement.</param>
public static void FloodFill<T>(this T source, int x, int y, int width, int height, T target, T replacement)
where T : IEquatable<T>
int i;
source.FloodFill(x, y, width, height, target, replacement, out i);
/// <summary>
/// Floods the array following Flood Fill algorithm
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source">The source.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="target">The target to replace.</param>
/// <param name="replacement">The replacement.</param>
/// <param name="i">The i.</param>
// This was generic
public static void FloodFill<T>(this T source, int x, int y, int width, int height, T target, T replacement, out int i)
where T : IEquatable<T>
i = 0;
HashSet<int> queue = new HashSet<int>();
queue.Add(P(x, y, width, height));
while (queue.Count > 0)
int _i = queue.First(),
_x = _i % width,
_y = _i / width;
queue.Remove(_i);
if (source[_i].Equals(target))
source[_i] = replacement;
for (int offsetX = -1; offsetX < 2; offsetX++)
for (int offsetY = -1; offsetY < 2; offsetY++)
if (i > 100000)
break;
I can't show the other code, but I can try to explain it.
Basically, we have this texture (https://themindheist.files.wordpress.com/2015/03/gta_usa_map3.png) (It's too big to be here).
- We iterate it pixel by pixel.
- If we found any allowed pixel (Grass, Rock, Ice, Snow or whatever) then...
- We start looking for the shape of the current biome
- Then before continuing iterating we call Flood Fill algorithm.
- With this call we ensure that we will never pass over any pixel that form part of any of the map's polygons.
But as you can see, I have problems.
Watching at my implementation I suppose that when enqueued pixels looks for neighbors they are trapped and they don't return any neighbor pixel.
Or maybe, this is the way my flood fill algorithm executes (under special conditions I don't know).
What could you suggest/recommend me to do?
Note: The texture was get when I manually exited the method. So, my fill algorithm is filling the texture by "layers" that's why there are so many yellow pixels.
c# algorithm unity3d optimization flood-fill
c# algorithm unity3d optimization flood-fill
edited Nov 14 '18 at 19:59
z3nth10n
asked Nov 14 '18 at 19:14
z3nth10nz3nth10n
95721124
95721124
You are missing marking pixels as visited. At the moment you can visit a node multiple times
– juvian
Nov 14 '18 at 20:12
I mark pixels as visited outside of the Flood Fill algorithm, and I suppose I do the same when I check!queue.Contains(targetIndex)
. In this case, what do you mean?
– z3nth10n
Nov 14 '18 at 20:18
1
You start with source. On the first step you remove it from the queue add its neighbour's to the queue. Now you remove first neighbor added from the queue and you will add source again to the queue because it is not in it anymore
– juvian
Nov 14 '18 at 20:22
So, it's better to do thisqueue.Remove(_i)
at the end or what do you suggest me?
– z3nth10n
Nov 14 '18 at 20:40
I created another forked fiddle: dotnetfiddle.net/jIhRSU and I see no differences, so I will check this. Also, I'm testing if I really need to check for Interloecked.
– z3nth10n
Nov 14 '18 at 20:41
|
show 4 more comments
You are missing marking pixels as visited. At the moment you can visit a node multiple times
– juvian
Nov 14 '18 at 20:12
I mark pixels as visited outside of the Flood Fill algorithm, and I suppose I do the same when I check!queue.Contains(targetIndex)
. In this case, what do you mean?
– z3nth10n
Nov 14 '18 at 20:18
1
You start with source. On the first step you remove it from the queue add its neighbour's to the queue. Now you remove first neighbor added from the queue and you will add source again to the queue because it is not in it anymore
– juvian
Nov 14 '18 at 20:22
So, it's better to do thisqueue.Remove(_i)
at the end or what do you suggest me?
– z3nth10n
Nov 14 '18 at 20:40
I created another forked fiddle: dotnetfiddle.net/jIhRSU and I see no differences, so I will check this. Also, I'm testing if I really need to check for Interloecked.
– z3nth10n
Nov 14 '18 at 20:41
You are missing marking pixels as visited. At the moment you can visit a node multiple times
– juvian
Nov 14 '18 at 20:12
You are missing marking pixels as visited. At the moment you can visit a node multiple times
– juvian
Nov 14 '18 at 20:12
I mark pixels as visited outside of the Flood Fill algorithm, and I suppose I do the same when I check
!queue.Contains(targetIndex)
. In this case, what do you mean?– z3nth10n
Nov 14 '18 at 20:18
I mark pixels as visited outside of the Flood Fill algorithm, and I suppose I do the same when I check
!queue.Contains(targetIndex)
. In this case, what do you mean?– z3nth10n
Nov 14 '18 at 20:18
1
1
You start with source. On the first step you remove it from the queue add its neighbour's to the queue. Now you remove first neighbor added from the queue and you will add source again to the queue because it is not in it anymore
– juvian
Nov 14 '18 at 20:22
You start with source. On the first step you remove it from the queue add its neighbour's to the queue. Now you remove first neighbor added from the queue and you will add source again to the queue because it is not in it anymore
– juvian
Nov 14 '18 at 20:22
So, it's better to do this
queue.Remove(_i)
at the end or what do you suggest me?– z3nth10n
Nov 14 '18 at 20:40
So, it's better to do this
queue.Remove(_i)
at the end or what do you suggest me?– z3nth10n
Nov 14 '18 at 20:40
I created another forked fiddle: dotnetfiddle.net/jIhRSU and I see no differences, so I will check this. Also, I'm testing if I really need to check for Interloecked.
– z3nth10n
Nov 14 '18 at 20:41
I created another forked fiddle: dotnetfiddle.net/jIhRSU and I see no differences, so I will check this. Also, I'm testing if I really need to check for Interloecked.
– z3nth10n
Nov 14 '18 at 20:41
|
show 4 more comments
0
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53307270%2fflood-filling-algorithm-doesnt-work-as-expected-it-creates-gaps-between-pixel%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
0
active
oldest
votes
0
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53307270%2fflood-filling-algorithm-doesnt-work-as-expected-it-creates-gaps-between-pixel%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
You are missing marking pixels as visited. At the moment you can visit a node multiple times
– juvian
Nov 14 '18 at 20:12
I mark pixels as visited outside of the Flood Fill algorithm, and I suppose I do the same when I check
!queue.Contains(targetIndex)
. In this case, what do you mean?– z3nth10n
Nov 14 '18 at 20:18
1
You start with source. On the first step you remove it from the queue add its neighbour's to the queue. Now you remove first neighbor added from the queue and you will add source again to the queue because it is not in it anymore
– juvian
Nov 14 '18 at 20:22
So, it's better to do this
queue.Remove(_i)
at the end or what do you suggest me?– z3nth10n
Nov 14 '18 at 20:40
I created another forked fiddle: dotnetfiddle.net/jIhRSU and I see no differences, so I will check this. Also, I'm testing if I really need to check for Interloecked.
– z3nth10n
Nov 14 '18 at 20:41