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