数组和链表实现种子填充的C++算法

种子填充

种子填充算法又称为边界填充算法。其基本思想是:从多边形区域的一个内点开始,由内向外用给定的颜色画点直到边界为止。如果边界是以一种颜色指定的,则种子填充算法可逐个像素地处理直到遇到边界颜色为止。
种子填充算法常用四连通域和八连通域技术进行填充操作。
从区域内任意一点出发,通过上、下、左、右四个方向到达区域内的任意像素。用这种方法填充的区域就称为四连通域;这种填充方法称为四向连通算法。
从区域内任意一点出发,通过上、下、左、右、左上、左下、右上和右下八个方向到达区域内的任意像素。用这种方法填充的区域就称为八连通域;这种填充方法称为八向连通算法。

代码

此处用八连通,前两个函数是对int型进行种子填充(分别基于数组和链表),第三个void是对char型处理。`#include"stdio.h"
说明:以下部分是与图像有关的,若不需要可以删除。实现的是将文件保存为.bmp格式。

bool saveBmp(const char* bmpName, unsigned char* imgBuf, int width, int height, int byteCount)
{
	if (!imgBuf)
		return 0;

	//灰度图像颜色表空间1024,彩色图像没有颜色表
	int colorTable = 0;
	if (byteCount == 1) colorTable = 1024;

	//一行象素字节数为4的倍数
	int lineByte = (width * byteCount + 3) / 4 * 4;

	FILE* fp;
	fopen_s(&fp, bmpName, "wb");
	if (fp == 0) return 0;

	//填写文件头
	BITMAPFILEHEADER fileHead;
	fileHead.bfType = 0x4D42;
	fileHead.bfSize =
		sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorTable + lineByte * height;
	fileHead.bfReserved1 = 0;
	fileHead.bfReserved2 = 0;
	fileHead.bfOffBits = 54 + colorTable;
	fwrite(&fileHead, sizeof(BITMAPFILEHEADER), 1, fp);

	// 填写信息头
	BITMAPINFOHEADER head;
	head.biBitCount = byteCount * 8;
	head.biClrImportant = 0;
	head.biClrUsed = 0;
	head.biCompression = 0;
	head.biHeight = height;
	head.biPlanes = 1;
	head.biSize = 40;
	head.biSizeImage = lineByte * height;
	head.biWidth = width;
	head.biXPelsPerMeter = 0;
	head.biYPelsPerMeter = 0;
	fwrite(&head, sizeof(BITMAPINFOHEADER), 1, fp);

	//颜色表拷贝  
	if (colorTable == 1024)
	{
		unsigned char table[1024];
		for (int i = 0; i < 256; i++)
		{
			*(table + i * 4 + 0) = i;
			*(table + i * 4 + 1) = i;
			*(table + i * 4 + 2) = i;
			*(table + i * 4 + 3) = 0;
		}
		fwrite(table, 1024, 1, fp);
	}

	//准备数据并写文件
	unsigned char* buf = new unsigned char[height * lineByte];
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width * byteCount; j++)
			*(buf + i * lineByte + j) = *(imgBuf + i * width * byteCount + j);
	}
	fwrite(buf, height * lineByte, 1, fp);

	delete[]buf;

	fclose(fp);

	return 1;
}

与图像互动的一部分(可删)

FILE* fp;

	fopen_s(&fp, "D:6.raw", "rb");

	m = 640, n = 640, seed_y = 154, seed_x = 187, thresh = 60;//6.raw

	unsigned char* buf = new unsigned char[m * n];

	fread(buf, sizeof(unsigned char), m * n, fp);

	fclose(fp);

	unsigned char* bufOut = new unsigned char[m * n];
	//regionGrowing_raw(buf, m, n, seed_y, seed_x,  thresh, bufOut);

	regionGrowing_byStackChain(buf, 640, 640, 154, 187, 60, bufOut);



	saveBmp("result", bufOut, n, m, 1);

	delete[]buf;
	delete[]bufOut;

完整代码如下

#include"math.h"
#include "Windows.h"

int currentPoint_x, currentPoint_y, popPoint_x, popPoint_y;
int i, j, k;//循环变量
int temp1, temp2;//临时变量,存放种子点以及待生长点的灰度值

struct point
{
	int x;
	int y;
};
struct node
{
	int x;
	int y;
	struct node* link;
};

bool saveBmp(const char* bmpName, unsigned char* imgBuf, int width, int height, int byteCount)
{
	if (!imgBuf)
		return 0;

	//灰度图像颜色表空间1024,彩色图像没有颜色表
	int colorTable = 0;
	if (byteCount == 1) colorTable = 1024;

	//一行象素字节数为4的倍数
	int lineByte = (width * byteCount + 3) / 4 * 4;

	FILE* fp;
	fopen_s(&fp, bmpName, "wb");
	if (fp == 0) return 0;

	//填写文件头
	BITMAPFILEHEADER fileHead;
	fileHead.bfType = 0x4D42;
	fileHead.bfSize =
		sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorTable + lineByte * height;
	fileHead.bfReserved1 = 0;
	fileHead.bfReserved2 = 0;
	fileHead.bfOffBits = 54 + colorTable;
	fwrite(&fileHead, sizeof(BITMAPFILEHEADER), 1, fp);

	// 填写信息头
	BITMAPINFOHEADER head;
	head.biBitCount = byteCount * 8;
	head.biClrImportant = 0;
	head.biClrUsed = 0;
	head.biCompression = 0;
	head.biHeight = height;
	head.biPlanes = 1;
	head.biSize = 40;
	head.biSizeImage = lineByte * height;
	head.biWidth = width;
	head.biXPelsPerMeter = 0;
	head.biYPelsPerMeter = 0;
	fwrite(&head, sizeof(BITMAPINFOHEADER), 1, fp);

	//颜色表拷贝  
	if (colorTable == 1024)
	{
		unsigned char table[1024];
		for (int i = 0; i < 256; i++)
		{
			*(table + i * 4 + 0) = i;
			*(table + i * 4 + 1) = i;
			*(table + i * 4 + 2) = i;
			*(table + i * 4 + 3) = 0;
		}
		fwrite(table, 1024, 1, fp);
	}

	//准备数据并写文件
	unsigned char* buf = new unsigned char[height * lineByte];
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width * byteCount; j++)
			*(buf + i * lineByte + j) = *(imgBuf + i * width * byteCount + j);
	}
	fwrite(buf, height * lineByte, 1, fp);

	delete[]buf;

	fclose(fp);

	return 1;
}
void regionGrowing1(int* buf, int m, int n, int seed_y, int seed_x, int thresh, int* bufOut)//数组型种子生长
{
	
	//将输出buf初始化置1, 1代表没生长过,0代表生长标记
	for (i = 0; i < m; i++) {
		for (j = 0; j < n; j++) {
			*(bufOut + i * n + j) = 1;
		}
	}

	//二维数组direction代表中心点8邻域坐标与该点在x和y方向上的偏移,
	//其中第一列为x方向的偏移,第二列为y方向的偏移
	int direction[8][2] = { { 0,1 },{ 1,1 },{ 1,0 },{ 1,-1 },{ 0,-1 },{ -1,-1 },{ -1,0 },{ -1,1 } };

	//栈申请,此处假定进栈的点最多为矩阵大小
	point* stack = new point[m * n];
	int top = -1;//栈顶指针

	//当前正处理的点和弹出的点
	int currentPoint_x, currentPoint_y, popPoint_x, popPoint_y;

	 //记录种子点的值
	temp1 = *(buf + seed_y * n + seed_x);
	//将给定种子点置标记0,入栈
	*(bufOut + seed_y * n + seed_x) = 0;
	top = 0;
	stack[top].x = seed_x;
	stack[top].y = seed_y;

	//堆栈
	while (top > -1) {
		//弹出栈顶元素,该点已经生长过
		popPoint_x = stack[top].x;
		popPoint_y = stack[top].y;
		top--;
		for (k = 0; k < 8; k++) {
			currentPoint_x = popPoint_x + direction[k][0];
			currentPoint_y = popPoint_y + direction[k][1];
			if (currentPoint_x<0 || currentPoint_x>n - 1 || currentPoint_y<0 || currentPoint_y>m - 1)
				continue;
			int g = *(bufOut + currentPoint_y * n + currentPoint_x);
			if (g == 1) {
				temp2 = *(buf + currentPoint_y*n + currentPoint_x);
				if (abs(temp1 - temp2) < thresh) {
					*(bufOut + currentPoint_y * n + currentPoint_x) = 0;
					top++;
					stack[top].x = currentPoint_x;
					stack[top].y = currentPoint_y;
				}
			}
		}

		//考察被弹出点周围是否有没有要生长的点


	}//while(top)

	 //清除缓冲区
	delete[]stack;
}
void regionGrowing_bystack(int* buf, int m, int n, int seed_y, int seed_x, int thresh, int* bufOut)
{
	//循环变量
	int i, j, k; struct node* p = new struct node;
	//将输出buf初始化置1, 1代表没生长过,0代表生长标记
	for (i = 0; i < m * n; ++i) { bufOut[i] = 1; }


	//二维数组direction代表中心点8邻域坐标与该点在x和y方向上的偏移,
	//其中第一列为x方向的偏移,第二列为y方向的偏移
	int direction[8][2] = { { 0,1 },{ 1,1 },{ 1,0 },{ 1,-1 },{ 0,-1 },{ -1,-1 },{ -1,0 },{ -1,1 } };

	//栈申请,此处假定进栈的点最多为矩阵大小
	struct node* head = new node;
	 head->link = p;




	//当前正处理的点和弹出的点
	int currentPoint_x, currentPoint_y, popPoint_x, popPoint_y;

	int temp1, temp2;//临时变量,存放种子点以及待生长点的灰度值

					 //记录种子点的值
	temp1 = *(buf + seed_y * n + seed_x);
	//将给定种子点置标记0,入栈

	p->x = seed_x; p->y = seed_y; p->link = 0;
	bufOut[seed_y * n + seed_x] = 0;
	while (head->link != 0) {
		p = head->link;
		popPoint_x = p->x;
		popPoint_y = p->y;
		head->link = p->link; delete p;
		bufOut[popPoint_x + popPoint_y * n] = 0;
		for (i = 0; i < 8; i++) {
			currentPoint_x = popPoint_x + direction[i][0]; currentPoint_y = popPoint_y + direction[i][1];
			if (bufOut[currentPoint_x + currentPoint_y * n] == 1) {
				if (abs(temp1 - buf[currentPoint_x + currentPoint_y * n]) < thresh) {
					struct node* p = new node;
					p->x = currentPoint_x;
					p->y = currentPoint_y;
					p->link = head->link;
					head->link = p;

				}
			}
		}
	}

}
void regionGrowing_byStackChain(unsigned char* buf, int m, int n, int seed_y, int seed_x, int thresh, unsigned char* bufOut)
{
	int currentPoint_x, currentPoint_y, popPoint_x, popPoint_y;
	int k, i, j;
	int temp1, temp2;
	int direction[8][2] = { { 0,1 },{ 1,1 },{ 1,0 },{ 1,-1 },{ 0,-1 },{ -1,-1 },{ -1,0 },{ -1,1 } };
	temp1 = *(buf + seed_y * n + seed_x);
	//栈申请,此处假定进栈的元素最多为矩阵大小
	for (i = 0; i < m; i++)
	{
		for (j = 0; j < n; j++)
		{
			bufOut[i * n + j] = 255;//每一行每一列的元素置1
		}
	}
	node* stack, * q;
	//将给定种子点置0,入栈
	bufOut[seed_y * n + seed_x] = 0;
	stack = new node;
	stack->y = seed_y;
	stack->x = seed_x;
	stack->link = 0;

	while (stack != 0)
	{//堆栈
   //弹出栈顶元素,该元素已经生长过
		popPoint_x = stack->x;
		popPoint_y = stack->y;
		q = stack;
		stack = stack->link;
		delete q;
		for (k = 0; k < 8; k++)
		{//考察被弹出元素周围是否有没有生长的元素
			currentPoint_x = popPoint_x + direction[k][0];
			currentPoint_y = popPoint_y + direction[k][1];
			if (currentPoint_x<0 || currentPoint_x>n - 1 || currentPoint_y<0 || currentPoint_y>m - 1)
			{
				continue;
			}
			int t = bufOut[currentPoint_y * n + currentPoint_x];
			if (t == 255)
			{
				temp2 = buf[currentPoint_y * n + currentPoint_x];
				if (abs(temp1 - temp2) < thresh)
				{
					bufOut[currentPoint_y * n + currentPoint_x] = 0;
					q = new node;
					q->y = currentPoint_y;
					q->x = currentPoint_x;
					q->link = stack;
					stack = q;
				}
			}
		}
	}
}




void main()
{
	int s[] = {
		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
		1, 1, 8, 9, 7, 7, 8, 9, 2, 2, 1,
		1, 2, 7, 8, 8, 8, 8, 9, 1, 1, 2,
		1, 1, 1, 8, 8, 8, 7, 8, 1, 1, 1,
		2, 2, 2, 7, 7, 8, 9, 8, 1, 1, 1,
		1, 1, 1, 2, 7, 7, 8, 1, 1, 1, 1,
		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
	};
	int result[7 * 11];
	int i, j;
	regionGrowing1(s, 7, 11, 3, 5, 3, result);
	printf("原矩阵为下\n");
	for (i = 0; i < 7; i++) {
		for (j = 0; j < 11; j++) {
			printf("%3d", s[i * 11 + j]);
		}
		printf("\n");
	}
	printf("生长矩阵为下\n");
	for (i = 0; i < 7; i++) {
		for (j = 0; j < 11; j++) {
			printf("%3d", result[i * 11 + j]);
		}
		printf("\n");
	}
	
	int m, n, seed_x, seed_y, thresh;

	FILE* fp;

	fopen_s(&fp, "D:6.raw", "rb");

	m = 640, n = 640, seed_y = 154, seed_x = 187, thresh = 60;//6.raw

	unsigned char* buf = new unsigned char[m * n];

	fread(buf, sizeof(unsigned char), m * n, fp);

	fclose(fp);

	unsigned char* bufOut = new unsigned char[m * n];
	//regionGrowing_raw(buf, m, n, seed_y, seed_x,  thresh, bufOut);

	regionGrowing_byStackChain(buf, 640, 640, 154, 187, 60, bufOut);



	saveBmp("result", bufOut, n, m, 1);

	delete[]buf;
	delete[]bufOut;
	

	int t;
	scanf_s("%d", &t);
}`
种子填充算法,自己写的,希望对大家有用 // 种子法View.cpp : implementation of the CMyView class // #include "stdafx.h" #include "种子法.h" #include "种子法Doc.h" #include "种子法View.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif struct point { int x; int y; }p[10]={200,100,100,200,150,100,200,300,250,100,300,200,-1}; point stack[1024000]; int top; void push(int x,int y) { if(top>1024000)exit(0); stack[top].x=x; stack[top].y=y; top++; } void pop(int &x,int &y) { if(top==0) exit(0); x=stack[top-1].x; y=stack[top-1].y; top--; } void gettop(int &x,int &y) { if(top==0) exit(0); x=stack[top-1].x; y=stack[top-1].y; } ///////////////////////////////////////////////////////////////////////////// // CMyView IMPLEMENT_DYNCREATE(CMyView, CView) BEGIN_MESSAGE_MAP(CMyView, CView) //{{AFX_MSG_MAP(CMyView) ON_WM_LBUTTONDOWN() //}}AFX_MSG_MAP // Standard printing commands ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CMyView construction/destruction CMyView::CMyView() { // TODO: add construction code here } CMyView::~CMyView() { } BOOL CMyView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return CView::PreCreateWindow(cs); } ///////////////////////////////////////////////////////////////////////////// // CMyView drawing void CMyView::OnLButtonDown(UINT nFlags, CPoint point) { int x,y; CClientDC dc(this); // TODO: Add your message handler code here and/or call default origin=point; push(origin.x,origin.y); while(top!=0) { pop(x,y); if(dc.GetPixel(x-1,y)!=0)//不等于边界色 { dc.SetPixel(x-1,y,0);//染成黑色 push(x-1,y); //加入栈 } if(dc.GetPixel(x+1,y)!=0) { dc.SetPixel(x+1,y,0); push(x+1,y); } if(dc.GetPixel(x,y-1)!=0) { dc.SetPixel(x,y-1,0); push(x,y-1); } if(dc.GetPixel(x,y+1)!=0) { dc.SetPixel(x,y+1,0); push(x,y+1); } } CView::OnLButtonDown(nFlags, point); } void CMyView::OnDraw(CDC* pDC) { CClientDC dc(this); dc.TextOut(1,5,"请为每个区选种子,务必在图形内"); CMyDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); int i; for(i=0;p[i+1].x!=-1;i++) { dc.MoveTo(p[i].x,p[i].y); dc.LineTo(p[i+1].x,p[i+1].y); } dc.MoveTo(p[i].x,p[i].y); dc.LineTo(p[0].x,p[0].y); // TODO: add draw code for native data here } ///////////////////////////////////////////////////////////////////////////// // CMyView printing BOOL CMyView::OnPreparePrinting(CPrintInfo* pInfo) { // default preparation return DoPreparePrinting(pInfo); } void CMyView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add extra initialization before printing } void CMyView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add cleanup after printing } ///////////////////////////////////////////////////////////////////////////// // CMyView diagnostics #ifdef _DEBUG void CMyView::AssertValid() const { CView::AssertValid(); } void CMyView::Dump(CDumpContext& dc) const { CView::Dump(dc); } CMyDoc* CMyView::GetDocument() // non-debug version is inline { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMyDoc))); return (CMyDoc*)m_pDocument; } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CMyView message handlers
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值