本文给出三个实区域填充算法的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;
}
这里给出种子扫描线算法的填充结果: