问题
so far i have implemented a floodfill algorithm. I wanted to tweak it, so that it would leave out the edge. To demonstrate this i uploaded an image:

Image 1 is the image that i want to modify. Image 3 is what my algorithm is supposed to do. Image 2 is my current result.
So in this case the targetColor is white and the replacementColor is green;
Here is pseudocode of what i have done so far.
doFloodFill(x,y,targetColor,replacementcolor) {
if (x and y not in bounds of image) {
return
}
if (color(x,y) IS NOT targetColor) {
return
}
if (color(x+1, y) IS NOT targetColorOfFloodFill AND color(x+1, y) IS NOT replacementColor OR
color(x-1, y) IS NOT targetColorOfFloodFill AND color(x-1, y) IS NOT replacementColor OR
color(x, y+1) IS NOT targetColorOfFloodFill AND color(x, y+1) IS NOT replacementColor OR
color(y, y-1) IS NOT targetColorOfFloodFill AND color(x, y-1) IS NOT replacementColor) {
return;
}
image.setColor(x, y, replacementColor)
doFloodFill(x+3,y,targetcolor,replacementcolor)
doFloodFill(x-3,y,targetcolor,replacementcolor)
doFloodFill(x,y+3,targetcolor,replacementcolor)
doFloodFill(x,y-3,targetcolor,replacementcolor)
}
This tweak is implemented into my floodfill. Leaving it out results in a working floodFill algorithm without any problems. The actual question would be: how can i differentiate an edge pixel from a pixel with different color within the area?
P.S: we can assume that x, y are starting from within the area
回答1:
I would go as well for the floodfill complement.
Still, an other idea:
- Floodfill like usual
- Keep track of one pixel of the border: e.g pixel at the utmost top
- Then follow the border like a mouse looking for escape and make it white again.
const canvas = document.querySelector('canvas');
const M = `
00000000000000000000
00000110011111110000
00001111111110000000
00011111111111100000
00111111111101110010
01111111101111110010
01111111111111110110
01111111111111111110
01111111111111111100
01111111111111111100
01111111111111111100
01111111111111111000
00111111111111111000
00111111111111110000
00011111111111100000
00000000000000000000
`.trim().split('\n').map(x=>x.trim().split('').map(x=>parseInt(x)))
const mat = ({ x, y }, v) => {
if (v) {
M[y][x] = v
}
return M[y][x]
}
const left = ({x,y}) => ({ x: y, y: -x })
const right = ({x,y}) => ({ x: -y, y: x })
const back = ({x, y}) => ({ x: -x, y: -y})
const front = (pos, { x, y }) => ({ x: pos.x + x, y: pos.y + y })
const splinter = {
pos: {
x: 5,
y: 1
},
orig: {
x: 5,
y: 1
},
dir: { x: 1, y: 0 },
atStart() {
return this.pos.x === this.orig.x && this.pos.y === this.orig.y
},
move () {
if (this.atStart() && mat(this.pos) === 2) { return false }
// wall on left
if (mat(front(this.pos, left(this.dir))) === 0) {
// wall on front
if (mat(front(this.pos, this.dir)) === 0) {
// wall on right
if (mat(front(this.pos, right(this.dir))) === 0) {
this.dir = back(this.dir)
} else {
this.dir = right(this.dir)
}
}
this.poop()
} else {
this.dir = left(this.dir)
}
this.moveForward()
return true
},
moveForward () {
this.pos.x += this.dir.x
this.pos.y += this.dir.y
},
poop () {
mat({ x: this.pos.x, y: this.pos.y }, 2)
},
sprite () {
if (this.atStart()) { return 'X' }
if (this.dir.x === -1 && this.dir.y === 0) { return '←' }
if (this.dir.x === 1 && this.dir.y === 0) { return '→'}
if (this.dir.x === 0 && this.dir.y === 1) { return '↓' }
if (this.dir.x === 0 && this.dir.y === -1) { return '↑' }
}
}
function redraw () {
const ctx = canvas.getContext('2d')
const dw = canvas.width / M[0].length
const dh = canvas.height / M.length
const fill = ({ x, y }, color) => {
ctx.fillStyle = color
ctx.fillRect(x * dw, y * dh, dw, dh)
}
const colors = {
1: 'green',
0: 'black',
2: 'white'
}
M.forEach((row, i) => {
row.forEach((el, j) => {
fill({ x: j, y: i }, colors[el])
})
})
const char = splinter.sprite()
ctx.strokeText(char, (splinter.pos.x + 0.1) * dw, (splinter.pos.y + 0.8) * dh)
}
redraw()
document.querySelector('button').onclick = _ => {
splinter.move(); redraw()
}
document.querySelector('button.allmoves').onclick = _ => {
while(splinter.move()){}
redraw()
}
canvas{background:#eeeeee;}
<canvas width="160" height="160"></canvas>
<button>move, rat</button>
<button class="allmoves">move for your life, rat</button>
回答2:
First flood fill the black outer area in image 1 for example by starting with the pixel in the upper left corner of the image. Either use a color you haven't used yet (purple for example) or construct a mask during the filing.
Then fill the white area green in the central object like you did but without any tweaks of the algorithm. Just ordinary flood filling.
Finally, go through all the pixels in the second fill and turn those that border the first fill white again.
You have achieved your goal. If you did not use masks, make sure to fill the area resulting from the first fill black again.
No tweaking of the flood fill algorithm was needed.
来源:https://stackoverflow.com/questions/59240491/floodfill-algorithm-leaving-out-the-edge