实区域种子填充算法

本文给出三个实区域填充算法的c++实现。三个填充算法分别为边界填充算法、泛洪填充算法、扫描线种子填充算法,相关的理论与算法描述这里不涉及。

边界填充算法

st int direction[] = { 1, 0, -1, 0, 0, 1, 0, -1,  1, 1, 1, -1, -1, 1, -1, -1 };

void BoundaryFill4(HDC hdc, int x, int y, COLORREF fill_color, COLORREF boundary_color)
{
  COLORREF cur_color = GetPixel(hdc, x, y);
  if ((cur_color != boundary_color) && (cur_color != fill_color)) {
    SetPixel(hdc, x, y, fill_color);
    for (int i = 0; i < sizeof(direction) / sizeof(direction[0]) / 2; i += 2) {
      BoundaryFill4(hdc, x + direction[i], y + direction[i + 1], fill_color, boundary_color);
    }
  }
}

void BoundaryFill8(HDC hdc, int x, int y, COLORREF fill_color, COLORREF boundary_color)
{
  COLORREF cur_color = GetPixel(hdc, x, y);
  if ((cur_color != boundary_color) && (cur_color != fill_color)) {
    SetPixel(hdc, x, y, fill_color);
    for (int i = 0; i < sizeof(direction) / sizeof(direction[0]); i += 2) {
      BoundaryFill8(hdc, x + direction[i], y + direction[i + 1], fill_color, boundary_color);
    }
  }
}

泛洪填充算法

void FloodFill4(HDC hdc, int x, int y, int fill_color, int old_color)
{
  COLORREF cur_color = GetPixel(hdc, x, y);
  if (cur_color == old_color) {
    SetPixel(hdc, x, y, fill_color);
    int z = sizeof(direction) / sizeof(direction[0]) / 2;
    for (int i = 0; i < sizeof(direction) / sizeof(direction[0]) / 2; i += 2) {
      FloodFill4(hdc, x + direction[i], y + direction[i + 1], fill_color, old_color);
    }
  }
}

void FloodFill8(HDC hdc, int x, int y, int fill_color, int old_color)
{
  COLORREF cur_color = GetPixel(hdc, x, y);
  if (cur_color == old_color) {
    SetPixel(hdc, x, y, fill_color);
    for (int i = 0; i < sizeof(direction) / sizeof(direction[0]); i += 2) {
      FloodFill4(hdc, x + direction[i], y + direction[i + 1], fill_color, old_color);
    }
  }
}

扫描线种子填充算法

void ScanLineSeedFill(HDC hdc, RECT re, int x, int y, int fill_color, int boundary_color)
{
  if (x < re.left || x > re.right || y < re.top || y > re.bottom) return;

  std::stack<POINT> point_stack;
  
  point_stack.push(POINT{ x, y });
  while (!point_stack.empty()) {
    POINT point = point_stack.top();
    point_stack.pop();

    int x = point.x, y = point.y;
    if ((GetPixel(hdc, x, y) & 0xFFFFFF) == boundary_color)
      continue;
    std::tuple<int, int> interval = FindInterval(hdc, re, x, y, fill_color, boundary_color);
    std::vector<int> top_seeds = FindSeeds(hdc, std::get<0>(interval), std::get<1>(interval),
                                           y - 1, fill_color, boundary_color);
    std::vector<int> bottom_seeds = FindSeeds(hdc, std::get<0>(interval), std::get<1>(interval),
                                              y + 1, fill_color, boundary_color);
    std::for_each(std::begin(top_seeds), std::end(top_seeds), [&point_stack, y](int x) { point_stack.push(POINT{ x, y - 1 }); });
    std::for_each(std::begin(bottom_seeds), std::end(bottom_seeds), [&point_stack, y](int x) { point_stack.push(POINT{ x, y + 1 }); });
  }
}


std::tuple<int, int> FindInterval(HDC hdc, RECT re, int x, int y, int fill_color, int boundary_color)
{
  int left = x, right = x, tmp_x = x;

  if ((GetPixel(hdc, x, y) & 0xFFFFFF) != boundary_color)
    SetPixel(hdc, x, y, fill_color);
  for (tmp_x = x; --tmp_x >= re.left;) {
    if ((GetPixel(hdc, tmp_x, y) & 0xFFFFFF) == boundary_color)
      break;
    SetPixel(hdc, tmp_x, y, fill_color);
  }
  left = tmp_x + 1;
  for (tmp_x = x; ++tmp_x < re.right;) {
    if ((GetPixel(hdc, tmp_x, y) & 0xFFFFFF) == boundary_color)
      break;
    SetPixel(hdc, tmp_x, y, fill_color);
  }
  right = tmp_x - 1;
  return std::make_tuple(left, right);
}


std::vector<int> FindSeeds(HDC hdc, int x_left, int x_right, int y, int fill_color, int bounary_color)
{
  std::vector<int> right_most;
  bool in_fill_area = false;

  for (int i = x_left; i <= x_right; ++i) {
    int cur_color = GetPixel(hdc, i, y) & 0xFFFFFF;
    if (!in_fill_area && cur_color != fill_color && cur_color != bounary_color) {
      in_fill_area = true;
    } else if (in_fill_area && (cur_color == fill_color || cur_color == bounary_color)) {
      in_fill_area = false;
      right_most.push_back(i - 1);
    }
    if (i == x_right && in_fill_area)
      right_most.push_back(i);
  }
  return right_most;
}

这里给出种子扫描线算法的填充结果:

posted @ 2016-04-19 15:22  Leptus  阅读(2063)  评论(0编辑  收藏  举报