多边形填充——代码

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/guanyuqiu/article/details/53010025
typedef struct _IVT_TEDGE
{
	float  x;
	float  dx;
	int    ymax;
	struct _IVT_TEDGE*   Next;
}IVT_EDGE;

/************************************************************************/
/* 函数名:CreateROIImage
   说明:  重建图像感兴趣区域
   输入:  polygon - 多边形顶点
           nPolygonNUM—多边形顶点个数
           nWidth—图像宽度
           nHeight—图像高度
   输出:  无
   返回:  创建的图像感兴趣区域
/************************************************************************/
bool CreateROIImage(unsigned char *pImageROI,IVT_POINT* polygon, int nWidth, int nHeight, int nPolygonNUM)
{
	if (pImageROI == NULL)
	{
		return false;
	}
	memset(pImageROI, 0, nWidth * nHeight*sizeof(unsigned char));
	memset(pVIBESamples,0, nWidth*nHeight*sizeof(unsigned char));
	ScanFill(polygon, nPolygonNUM, pImageROI, nWidth,nHeight);
	return true;
}
/************************************************************************/
/* 函数名:ScanFill
   说明:多边形填充的主体程序
   输入:plolygonNum—多边形顶点个数
         polygon—指向多边形顶点的指针数组
   输出:pImage—感兴趣区域图像数据*/
/************************************************************************/
void ScanFill(IVT_POINT* polygon, int polygonNum, unsigned char *pImage, int nWidth, int nHeight)
{
	IVT_EDGE  **edges,*active;
	int        i,scan,scanmax = 0, scanmin = nHeight;
	//计算所有多边形顶点坐标中y的最大值和最小值,以此作为扫描线的处理范围
	for (i = 0; i < polygonNum/* - 1*/; i++)
	{
		if (scanmax < polygon[i].y)
		{
			scanmax = polygon[i].y;
		}
		if (scanmin > polygon[i].y)
		{
			scanmin = polygon[i].y;
		}
	}
	//初始化每条扫描线的边链表
	edges = (IVT_EDGE**)malloc(sizeof(IVT_EDGE*)*(scanmax - scanmin + 1));
	for (scan = scanmin; scan <= scanmax; scan++)
	{
		edges[scan - scanmin] = NULL;
	}
	BuildEdgeList(polygonNum, polygon, edges, scanmin);         //建立有序边表
	active = NULL;
	for (scan = scanmin; scan <= scanmax; scan++)      //扫描每条扫描线,求活性表
	{
		BuildActiveList((scan - scanmin), active, edges);          //建立活性边表
		if (active)
		{
			FillScan(scan,active,pImage,nWidth);             //填充当前扫描线
			UpdateActiveList(scan,active);            //更新活化边表
			ResortActiveList(active);                 //重排活化边表
		}
	}
	free((void*)edges);
}
/************************************************************************/
/* 函数名:BuildEdgeList
   说明:  创建边表的主体函数
   输入:  cnt—多边形顶点个数 
           pts—多边形顶点坐标
   输出:  edges[]—指向活性边结点的指针数组
   返回:  无*/
/************************************************************************/
void BuildEdgeList(int cnt, IVT_POINT* pts, IVT_EDGE* edges[],int yMin)
{
	IVT_EDGE*     edge;
	IVT_POINT     ps,pe,pss,pee;
	int           i;
	edge = (IVT_EDGE*)malloc(sizeof(IVT_EDGE));
	if (edge == NULL)
	{
		printf("edge malloc failed!\r\n");
	 	return;
	}
	for (i = 0; i < cnt; i++)
	{
		ps = pts[i];                       //当前处理边的起点
		pe = pts[(i+1) % cnt];           //当前处理边的终点
		pss = pts[(i-1+cnt) % cnt];    //起点的前一个相邻点
		pee = pts[(i+2) % cnt];          //终点的后一个相邻点
		if (ps.y != pe.y)                 //非水平线
		{
			edge->dx = (float)(pe.x - ps.x) / (float) (pe.y - ps.y);

			if (pe.y > ps.y)                             //当前顶点不是奇点,建立边表时使用下一个顶点的y值即yNext
			{
				edge->x = ps.x;
				if (pee.y >= pe.y)
				{
					edge->ymax = pe.y - 1;
				}
				else
				{
					edge->ymax = pe.y;
				}
				PushEdgeList(edges[ps.y - yMin],edge);
			}
			else
			{
				edge->x = pe.x;
				if (pss.y >= ps.y)
				{
					edge->ymax = ps.y - 1;
				}
				else
				{
					edge->ymax = ps.y;
				}
				PushEdgeList(edges[pe.y - yMin],edge);
			}
		}
	}
	free(edge);
}

/************************************************************************/
/*函数名: BuildActiveList
  说明:建立活性边表的主体函数,建立第scan条扫描线的活性边表
  输入:scan—扫描线行数
        edges—活性边列表
  输出:active—活性边表
  返回:无*/
/************************************************************************/
void BuildActiveList(int scan, IVT_EDGE* &active, IVT_EDGE* edges[])
{
	IVT_EDGE   *p,*q,*pA,*pA2;
	if (edges[scan] == NULL)
	{
		return;
	}
	p = edges[scan];             //查找当前扫描线对应的y桶
	q = p;
	while(p)
	{ 
		q = p;
		p = p->Next;
	}
	//对扫描线按照x值由小到大顺序添加
	if (!active)
	{ 
		active = edges[scan];
	}
	else
	{
		//添加到表头
		if (active->x > q->x)
		{
			q->Next = active;
			active = edges[scan];
		}
		else
		{
			//添加表中间或结尾
			pA = active;
			pA2 = pA;
			while(pA)
			{
				pA2 = pA;
				pA = pA->Next;
				if (pA)
				{
					if (pA->x > q->x)
					{
						break;
					}
				}
			}
			pA2->Next = edges[scan];
			q->Next = pA;

		}
	}
}
/************************************************************************/
/*函数名:FillScan
  说明:  填充一对交点的主体函数,填充扫描线上,且在下一结点到再下一结点之间的点
  输入:  scan—扫描线行数
          active—活动边表
  输出:  pImage—感兴趣区域图像
  返回:  无*/
/************************************************************************/
void FillScan(int scan, IVT_EDGE* active, unsigned char* pImage, int nWidth)
{
	IVT_EDGE  *p1,*p2;
	int       i;
	p1 = active;
	while (p1)
	{
		p2 = p1->Next;
		for (i = p1->x; i < p2->x; i++)
		{
			pImage[scan * nWidth + i]= 255;       //对图形内部的点置1
		}
		p1 = p2->Next;		                                     //活性表的下一条边表
		
	}
}
/************************************************************************/
/* 函数名: UpdateActiveList
   说明:   删除扫描线scan完成交点计算的活性边,同时更新交点x域
   输入:   scan—扫描线行数
   输出:   active—活动边表
   返回:	无*/
/************************************************************************/
void UpdateActiveList(int scan, IVT_EDGE* &active)
{
	IVT_EDGE  *q = active;
	IVT_EDGE  *p = active;
	IVT_EDGE  *pDelete = active;
	while(p)
	{
		if (scan >= p->ymax)              //扫描线超过边的最大y值,此条件的节点应该删掉
		{
			//删除表头
			if (active == p)
			{
				active = p->Next;
				pDelete = p;
				p = p->Next;
				q = p;
				free(pDelete);
			}
			else
			{
				//删除列表中间的结点
				q->Next = p->Next;
				pDelete = p;
				p = p->Next;
				free(pDelete);
			}
		} 
		else                               //扫描线未超过边的最大y值,相应的x值增加
		{
			p->x = p->x + p->dx;
			q = p;
			p = p->Next;
		}
	}
}

/************************************************************************/
/*函数名: ResortActiveList
  说明:   对活性边表节点重新排序的主体函数,活性边表active中的节点按照x值从小到大重新排序
  输入:
  输出:   active—活性边表
  返回;	   无*/
/************************************************************************/
void ResortActiveList(IVT_EDGE* &active)
{
	IVT_EDGE	*q;
	IVT_EDGE	*p = active;
	IVT_EDGE    *pMin;
	IVT_EDGE    *pChange;
	int         nMin;
	pChange = (IVT_EDGE*)malloc(sizeof(IVT_EDGE));
	while(p)
	{
		nMin = p->x;
		pMin = p;
		q = p;
		while(q)
		{
			if (nMin > q->x)
			{
				pMin = q;
				nMin = q->x;
			}
			q = q->Next;
		}
		if (pMin != p)
		{
			pChange->x = pMin->x;
			pChange->dx = pMin->dx;
			pChange->ymax = pMin->ymax;
			pMin->x = p->x;
			pMin->dx = p->dx;
			pMin->ymax = p->ymax;
			p->x = pChange->x;
			p->dx = pChange->dx;
			p->ymax = pChange->ymax;
		}
		p = p->Next;
	}
	free(pChange);
}


/************************************************************************/
/* 函数名:PushEdgeList
   说明:  把新放入边列表中
   输入:  Edge—新边
   输出:  List—边列表
   返回:  无*/
/************************************************************************/
void PushEdgeList(IVT_EDGE* &List, IVT_EDGE* Edge)
{
	IVT_EDGE   *p,*p2;
	p = List;
	p2 = List;
	if (List)
	{
		while(p)
		{
			p2 = p;
			p = p->Next;
		}
		p = (IVT_EDGE*)malloc(sizeof(IVT_EDGE));
		p->x = Edge->x;
		p->dx = Edge->dx;
		p->ymax = Edge->ymax;
		p->Next = NULL;
		p2 ->Next = p;
	}
	else
	{
		List = (IVT_EDGE*)malloc(sizeof(IVT_EDGE));
		List->x = Edge->x;
		List->dx = Edge->dx;
		List->ymax = Edge->ymax;
		List->Next = NULL;
	}
}

展开阅读全文

没有更多推荐了,返回首页