• Flood Fill 算法


    目录

    介绍

    概念

    参数

    实现方式

    四邻域填充

    dfs实现

    bfs实现

    八邻域填充

    dfs实现

    bfs实现

     扫描线算法


    --------------------------------------------------华丽的分割线------------------------------------------------------------


    介绍

    概念

    Flood Fill算法,又称洪水填充,泛洪算法

    其思想是:从一个种子点开始,将与其连通(可达且颜色相同/相近)的点全部染上另外一种颜色,直到所有可达节点都被染色为止。

    参数

    flood fill需要三个参数:待填充图像,起点,新颜色

    实现方式

    flood fill常用的有:四邻域flood fill,八邻域flood fill,扫描线算法

    其按实现方式又可分为:递归实现(dfs),队列实现(bfs),栈实现

    因为自己太菜篇幅有限,本篇只介绍dfs和bfs实现

    四邻域填充

    四邻域填充的思想是:给定一个点,将该点染色后,将其周围上下左右四个点进行染色(要染色的点颜色须和起点颜色相同/相近)

    dfs实现

    1. #include
    2. using namespace std;
    3. const int N = 145;
    4. int image[N][N];
    5. int n, m;
    6. int dir[4][2] = { -1,0,0,1,1,0,0,-1 };
    7. // 检查(x,y)是否可达
    8. bool check(int x, int y, int old_color, int new_color) {
    9. return x >= 0 && x < n && y >= 0 && y < m && image[x][y] == old_color && image[x][y] != new_color;
    10. }
    11. void flood_fill(int x, int y, int old_color, int new_color) {
    12. if (old_color == new_color) return; // 没有这个条件,在old_color和new_color相同时会无限递归
    13. image[x][y] = new_color; //填充当前点
    14. for (int i = 0; i < 4; i++) { // 遍历四个方向
    15. int nx = x + dir[i][0], ny = y + dir[i][1];
    16. if (check(nx, ny, old_color, new_color)) flood_fill(nx, ny, old_color, new_color);
    17. }
    18. }
    19. int main() {
    20. // 输入n*m的图像
    21. cin >> n >> m;
    22. for (int i = 0; i < n; i++)
    23. for (int j = 0; j < m; j++) cin >> image[i][j];
    24. // 输入起点和新颜色
    25. int sx, sy, new_color;
    26. cin >> sx >> sy >> new_color;
    27. // 洪水填充
    28. flood_fill(sx, sy, image[sx][sy], new_color);
    29. // 输出图像
    30. for (int i = 0; i < n; i++) {
    31. for (int j = 0; j < m; j++) cout << image[i][j] << " ";
    32. cout << endl;
    33. }
    34. return 0;
    35. }

    然而,使用dfs有一个致命缺陷:如果图像很大,填充时可能发生栈溢出

    bfs实现

    1. #include
    2. #include
    3. using namespace std;
    4. const int N = 145;
    5. int image[N][N];
    6. int n, m;
    7. int dir[4][2] = { -1,0,0,1,1,0,0,-1 };
    8. struct node {
    9. int x, y;
    10. node(int x, int y): x(x), y(y){}
    11. };
    12. queue q;
    13. // 检查(x,y)是否可达
    14. bool check(int x, int y, int old_color, int new_color) {
    15. return x >= 0 && x < n && y >= 0 && y < m && image[x][y] == old_color && image[x][y] != new_color;
    16. }
    17. // 给点(x,y)染色
    18. void stain(int x, int y, int color) {
    19. q.emplace(x, y);
    20. image[x][y] = color;
    21. }
    22. // start表示起点,new_color表示新颜色
    23. void flood_fill(node start, int new_color) {
    24. int sx = start.x, sy = start.y;
    25. int old_color = image[sx][sy];
    26. stain(sx, sy, new_color);
    27. while (q.size()) {
    28. node t = q.front();
    29. q.pop();
    30. for (int i = 0; i < 4; i++) {
    31. int nx = t.x + dir[i][0], ny = t.y + dir[i][1];
    32. if (check(nx, ny, old_color, new_color)) stain(nx, ny, new_color);
    33. }
    34. }
    35. }
    36. int main() {
    37. // 输入n*m的图像
    38. cin >> n >> m;
    39. for (int i = 0; i < n; i++)
    40. for (int j = 0; j < m; j++) cin >> image[i][j];
    41. // 输入起点和新颜色
    42. int sx, sy, new_color;
    43. cin >> sx >> sy >> new_color;
    44. // 洪水填充
    45. flood_fill(node(sx, sy), new_color);
    46. // 输出图像
    47. for (int i = 0; i < n; i++) {
    48. for (int j = 0; j < m; j++) cout << image[i][j] << " ";
    49. cout << endl;
    50. }
    51. return 0;
    52. }

    八邻域填充

    八邻域填充和四邻域填充类似,不过从一个点可以扩展到周围八个方向:上,下,左,右,左上,左下,右上,右下

    dfs实现

    1. #include
    2. using namespace std;
    3. const int N = 145;
    4. int image[N][N];
    5. int n, m;
    6. int dir[8][2] = {
    7. {-1, -1},
    8. {-1, 0},
    9. {-1, 1},
    10. {0, -1},
    11. {0, 1},
    12. {1, -1},
    13. {1, 0},
    14. {1, 1}
    15. };
    16. // 检查(x,y)是否可达
    17. bool check(int x, int y, int old_color, int new_color) {
    18. return x >= 0 && x < n&& y >= 0 && y < m&& image[x][y] == old_color && image[x][y] != new_color;
    19. }
    20. void flood_fill(int x, int y, int old_color, int new_color) {
    21. if (old_color == new_color) return; // 没有这个条件,在old_color和new_color相同时会无限递归
    22. image[x][y] = new_color; //填充当前点
    23. for (int i = 0; i < 8; i++) { // 遍历四个方向
    24. int nx = x + dir[i][0], ny = y + dir[i][1];
    25. if (check(nx, ny, old_color, new_color)) flood_fill(nx, ny, old_color, new_color);
    26. }
    27. }
    28. int main() {
    29. // 输入n*m的图像
    30. cin >> n >> m;
    31. for (int i = 0; i < n; i++)
    32. for (int j = 0; j < m; j++) cin >> image[i][j];
    33. // 输入起点和新颜色
    34. int sx, sy, new_color;
    35. cin >> sx >> sy >> new_color;
    36. // 洪水填充
    37. flood_fill(sx, sy, image[sx][sy], new_color);
    38. // 输出图像
    39. for (int i = 0; i < n; i++) {
    40. for (int j = 0; j < m; j++) cout << image[i][j] << " ";
    41. cout << endl;
    42. }
    43. return 0;
    44. }

    bfs实现

    1. #include
    2. #include
    3. using namespace std;
    4. const int N = 145;
    5. int image[N][N];
    6. int n, m;
    7. int dir[8][2] = {
    8. {-1, -1},
    9. {-1, 0},
    10. {-1, 1},
    11. {0, -1},
    12. {0, 1},
    13. {1, -1},
    14. {1, 0},
    15. {1, 1}
    16. };
    17. struct node {
    18. int x, y;
    19. node(int x, int y) : x(x), y(y) {}
    20. };
    21. queue q;
    22. // 检查(x,y)是否可达
    23. bool check(int x, int y, int old_color, int new_color) {
    24. return x >= 0 && x < n&& y >= 0 && y < m&& image[x][y] == old_color && image[x][y] != new_color;
    25. }
    26. // 给点(x,y)染色
    27. void stain(int x, int y, int color) {
    28. q.emplace(x, y);
    29. image[x][y] = color;
    30. }
    31. // start表示起点,new_color表示新颜色
    32. void flood_fill(node start, int new_color) {
    33. int sx = start.x, sy = start.y;
    34. int old_color = image[sx][sy];
    35. stain(sx, sy, new_color);
    36. while (q.size()) {
    37. node t = q.front();
    38. q.pop();
    39. for (int i = 0; i < 8; i++) {
    40. int nx = t.x + dir[i][0], ny = t.y + dir[i][1];
    41. if (check(nx, ny, old_color, new_color)) stain(nx, ny, new_color);
    42. }
    43. }
    44. }
    45. int main() {
    46. // 输入n*m的图像
    47. cin >> n >> m;
    48. for (int i = 0; i < n; i++)
    49. for (int j = 0; j < m; j++) cin >> image[i][j];
    50. // 输入起点和新颜色
    51. int sx, sy, new_color;
    52. cin >> sx >> sy >> new_color;
    53. // 洪水填充
    54. flood_fill(node(sx, sy), new_color);
    55. // 输出图像
    56. for (int i = 0; i < n; i++) {
    57. for (int j = 0; j < m; j++) cout << image[i][j] << " ";
    58. cout << endl;
    59. }
    60. return 0;
    61. }

     扫描线算法

    限于篇幅和作者能力,本篇不解释

  • 相关阅读:
    阿里云服务器的介绍和使用
    SpringSecurity简明教程
    CVE-2021-4034 polkit提权漏洞复现
    Android OTA差分包制作(RK平台)
    未登录拦截和登陆后直接跳转到当时想要跳的页面去
    js-es6-class转es5源码解析
    驱动day8
    极简的Http请求client推荐-OkHttp
    【初中生讲机器学习】12. 似然函数和极大似然估计:原理、应用与代码实现
    暑期JAVA学习(48)XML检索技术:Xpath
  • 原文地址:https://blog.csdn.net/sblsf/article/details/132639039