图形填充算法 (fill shape)

图形填充,主要是利用膨胀算法(flood fill 泛洪填充算法)来实现的,公式如下:

P(k+1) = (P(k) + B) ∩ A

A为图形,P(0) 为指定要填充图形内的一点,B 为模板,可以为点,为上下左右中点之类, 当 P(k+1) = P(k) 时算法结束,这里实现两个算法,

算法1:填充指定点,找指定点的上下左右的可填充点,压入栈,再取出栈点作为指定点,直到栈为空。

算法2:填充指定点所在行所有可填充点,再找指定点的上下行中所有的可填充线中的一点,压入栈,再取出栈点作为指定点,直到栈为空。

算法1与2,原理是一样的,都是上面公式的运用,算法1,栈太深空間復雜度過高,一般用算法2。

int draw_unit(unsigned char *data, unsigned char *p,  width, int height, int color)
{

	int i;
	int size =  width * height;
	for(i = 0; i < size; i++){
		if(p[i]){
			data[i] = color;
		}
	}
	return 0;
}

struct point{
	int x;
	int y;
};

struct point *point_init(int x, int y)
{
	struct point *p = (struct point *)malloc(sizeof(*p));
	//memset(p,0,sizeof(*p));
	p->x = x;
	p->y = y;
	return p;
}

int point_exit(struct point *p)
{
	free(p);
	return 0;
}

int stack_point_push(struct stack *s, int x, int y)
{
	assert(s);
	//printf("x:%d y:%d\n", x, y);
	struct point *p = point_init(x, y);
	stack_push(s, p);
	return 0;
}

int draw_point_is_vaild(unsigned char *data, unsigned char *p, int x, int y,  int width, int height)
{
	if(x < 0 || x >= width){
		return 0;
	}
	if(y < 0 || y >= height){
		return 0;
	}
	int offset = x + y*width;
	if(data[offset]){
		return 0;
	}
	if(p[offset]){
		return -1;
	}
	return 1;
}

int draw_point_cmp(struct stack *s, unsigned char *data, unsigned char *p, int x, int y,  int width, int height, int color)
{
	int xup, yup;
	int xdown, ydown;
	int xleft, yleft;
	int xright, yright;
	xup = x;yup = y - 1;
	xdown = x; ydown = y + 1;
	xleft = x - 1;yleft = y;
	xright = x + 1;yright = y;
	int result = draw_point_is_vaild(data, p, x, y,  width, height);
	if(result <= 0){
		return 0;
	}
	result = draw_point_is_vaild(data, p, xup, yup,  width, height);
	if(result > 0){
		stack_point_push(s, xup, yup);
	}
	result = draw_point_is_vaild(data, p, xdown, ydown,  width, height);
	if(result > 0){
		stack_point_push(s, xdown, ydown);
	}
	result = draw_point_is_vaild(data, p, xleft, yleft,  width, height);
	if(result > 0){
		stack_point_push(s, xleft, yleft);
	}
	result = draw_point_is_vaild(data, p, xright, yright,  width, height);
	if(result > 0){
		stack_point_push(s, xright, yright);
	}
	return 1;
}

int draw_point_line(struct stack *s, unsigned char *data, unsigned char *p, int x, int y,  int width, int height, int color)
{

	int i;
	int begin = x;
	int end = x;
	for(i = x; i >= 0; i--){
		int result = draw_point_is_vaild(data, p, i, y,  width, height);
		if(result == 0){
			break;
		}
		begin = i;
		draw_pixel(p,   width, height, 0, 0, i, y, color);
	}
	for(i = x; i < width; i++){
		int result = draw_point_is_vaild(data, p, i, y,  width, height);
		if(result == 0){
			break;
		}
		end = i;
		draw_pixel(p,   width, height, 0, 0, i, y, color);
	}
	int x2, y2;
	y2 = y - 1;
	x2 = -1;
	for(i = end; i >= begin; i--){
		int result = draw_point_is_vaild(data, p, i, y2,  width, height);
		if(result > 0 && x2 < 0){
			x2 = i;
			stack_point_push(s, x2, y2);
		}else if(result == 0){
			x2 = -1;
		}
	}
	y2 = y + 1;
	x2 = -1;
	for(i = end; i >=begin; i--){
		int result = draw_point_is_vaild(data, p, i, y2,  width, height);
		if(result > 0 && x2 < 0){
			x2 = i;
			stack_point_push(s, x2, y2);
		}else if(result == 0){
			x2 = -1;
		}
	}
	return 0;
}

int draw_fill2(unsigned char *data, unsigned char *p,   int width, int height, int x, int y, int color)
{

	int count = 0;

	struct point *point;
	struct stack *s = stack_init();
	draw_point_cmp(s, data, p, x, y,   width, height, color);
	int n = 0;
	int max = 0;
	while((point = stack_pop(s))){
		x = point->x;	
		y = point->y;	
		point_exit(point);
		int result = draw_point_line(s, data, p, x, y,   width, height, color);
		int size = stack_size(s);
		if(size > max){
			max = size;
		}
		count++;
	}
	printf("count:%d -- %d stack max:%d\n", count, n, max);
	stack_exit(s);
	return 0;
}

int draw_fill(unsigned char *data,   int width, int height, int *points, int size, int color)
{

	int rowbytes =  width;
	unsigned char *p = (unsigned char *)malloc(rowbytes * height);
	memset(p, 0, sizeof(rowbytes * height));

	int i;
	for(i = 0;i < size -1; i+=2){
		int x, y;
		x = points[i];
		y = points[i+1];
		
		draw_fill2(data, p,   width, height, x, y, color);
	}
	draw_unit(data, p,  width, height, color);
	free(p);
	return 0;
}

int draw_fill3(unsigned char *data,   int width, int height, int color)
{

	int rowbytes =  width;
	unsigned char *p = (unsigned char *)malloc(rowbytes * height);
	memset(p, 0, sizeof(rowbytes * height));
	int count = 0;
	int x = 500;
	int y = 500;

	struct point *point;
	struct stack *s = stack_init();
	draw_point_cmp(s, data, p, x, y,   width, height, color);
	int n = 0;
	int max = 0;
	while((point = stack_pop(s))){
		x = point->x;	
		y = point->y;	
		point_exit(point);
		int result = draw_point_cmp(s, data, p, x, y,   width, height, color);
		if(result){
			draw_pixel(p,   width, height, 0, 0, x, y, color);
			n++;
		}
		int size = stack_size(s);
		if(size > max){
			max = size;
		}
		count++;
	}
	printf("count:%d -- %d stack max:%d\n", count, n, max);
	stack_exit(s);
	draw_unit(data, p,  width, height, color);
	free(p);
	return 0;
}

stack 加上代码:

//stack.c
#include "stack.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct stack_node *stack_node_init(void *data){
	struct stack_node *s = (struct stack_node *)malloc(sizeof(*s));
	s->next = NULL;
	s->data = data;
	return s;
}
void stack_node_exit(struct stack_node *node){

	if(node->data){
		free(node->data);
	}
	free(node);
}

struct stack *stack_init(){
	struct stack *s = (struct stack *)malloc(sizeof(*s));
	s->next = NULL;
	s->num = 0;
	return s;
}

void *stack_push(struct stack *s, void *data){
	struct stack_node *node = stack_node_init(data);
	node->next = s->next;
	s->next = node;
	s->num++;
}

void *stack_pop(struct stack *s)
{
	void *data;
	struct stack_node *node;
	if(s->next){
		node = s->next;
		s->next = node->next;
		s->num--;

		data = node->data;
		node->data = NULL;
		stack_node_exit(node);
		return data;
	}else{
		return NULL;
	}
}

int stack_size(struct stack *s)
{
	return s->num;
}

void stack_exit(struct stack *s)
{
	struct stack_node *node;
	while((node = stack_pop(s)) != NULL){
		stack_node_exit(node);
	}
}

//stack.h
#ifndef STACK_H_H_
#define STACK_H_H_

struct stack_node{
	void *data;
	struct stack_node *next;
};

struct stack{
	struct stack_node *next;
	int num;
};

struct stack *stack_init();
void *stack_push(struct stack *s, void *data);
void *stack_pop(struct stack *s);
int stack_size(struct stack *s);
void stack_exit(struct stack *s);
#endif

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
区域四邻接点填充算法是一种用于图像处理和计算机图形学中的填充算法。它的目标是找到指定区域的连通内部点,并对其进行填充。以下是一个使用Python编写的简单区域四邻接点填充算法示例: ```python import numpy as np import cv2 def region_fill(image, seed_point, fill_color): # 获取图像尺寸 rows, cols = image.shape[:2] # 判断种子点是否在图像范围内 if seed_point[0] < 0 or seed_point[0] >= rows or seed_point[1] < 0 or seed_point[1] >= cols: return # 创建一个与原图像大小相同的用于存储填充结果的数组,初始化为0 filled = np.zeros_like(image) # 创建一个堆栈,用于保存待处理的像素点 stack = [] # 将种子点添加到堆栈中 stack.append(seed_point) # 获取种子点的颜色 seed_color = image[seed_point] # 定义四邻接点的偏移量 offsets = [(0, 1), (1, 0), (0, -1), (-1, 0)] while len(stack) > 0: # 从堆栈中弹出一个像素点 current_point = stack.pop() # 将当前像素点标记为已填充 filled[current_point] = 1 # 遍历四邻接点 for offset in offsets: # 计算四邻接点的坐标 neighbor_point = (current_point[0] + offset[0], current_point[1] + offset[1]) # 判断邻点是否在图像范围内 if neighbor_point[0] >= 0 and neighbor_point[0] < rows and neighbor_point[1] >= 0 and neighbor_point[1] < cols: # 判断邻点是否已经填充过 if filled[neighbor_point] == 0: # 判断邻点的颜色是否与种子点颜色相同 if np.array_equal(image[neighbor_point], seed_color): # 将邻点添加到堆栈中 stack.append(neighbor_point) # 将填充结果赋值给原图像 image[filled == 1] = fill_color # 加载原图像 image = cv2.imread("image.png") # 指定种子点 seed_point = (50, 50) # 指定填充颜色 fill_color = (255, 0, 0) # 调用区域四邻接点填充算法 region_fill(image, seed_point, fill_color) # 显示填充结果 cv2.imshow("Filled Image", image) cv2.waitKey(0) cv2.destroyAllWindows() ``` 以上代码通过Python中的OpenCV库实现了区域四邻接点填充算法。首先加载原图像,并指定一个种子点和填充颜色,然后调用`region_fill`函数进行填充,最后显示填充结果。算法利用一个堆栈来保存待处理的像素点,并使用一个填充结果数组来记录已填充的点。通过遍历四邻接点,并根据其颜色与种子点颜色的比较来确定是否进行填充操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值