计算机图形学 实验5 区域填充——种子填充算法(MFC中)

实验目的:

  1. 理解多边形填充的目的
  2. 掌握多边形的各种填充算法
    实验内容:
    一、编写程序实现四连通种子填充算法
    算法原理:
    算法的输入:种子点坐标(x,y),要填充的颜色
    以种子点为起点,查看它是否是边界(根据颜色) 或者是否已经被填充。
    如果是,则返回,否则填充该像素,并用一个邻接的像素作为新的种子进行递归。
    算法步骤:
    a) 种子像素压入栈中;
    b) 如果栈为空,则转e);否则转c);
    c) 弹出一个像素,并将该像素置成填充色;并判断该像素相邻的四连通像素是否为边界色或已经置成多边形的填充色,若不是,则将该像素压入栈;
    d) 转b);
    e) 结束。
    实现步骤:
  3. 在项目名称上右键——添加——类,输入类名stack_node,新建一个栈元素结构类,类里的成员包括:
    CPoint PixelPoint;
    Stack_node *Next;
  4. 在**View.h文件中添加 #include “stack_node.h”
  5. 在**View类中(**View.h文件)添加数据成员
    CPoint Point[4];//new:定义多边形
    CPoint Seed,PointLeft,PointTop,PointRight,PointBottom;//种子及其四个相邻点
    Stack_node *Head,*Base,*Last;//结点指针
  6. 在**View类中(**View.h文件)添加成员函数
    void PolygonFill();//区域填充
    void Push(CPoint point);//入栈
    Stack_node *Pop();//出栈
  7. 在**View类的构造函数(**View.cpp文件)中进行数据成员的初始化
    Point[0] = CPoint(20,20);
    Point[1] = CPoint(20,300);
    Point[2] = CPoint(60,60);
    Point[3] = CPoint(300,20);
    Head = Last = NULL;
  8. 在**View.cpp文件中实现入栈和出栈的成员函数
    void **View::Push(CPoint point)//入栈函数
    {
    Base=new Stack_node;
    Base->PixelPoint=point;
    Base->Next=NULL;
    if(Head==NULL)//空链
    {
    Last = Head = Base;
    }
    else
    {
    Last->Next=Base;
    Last = Base;
    }
    }

Stack_node * **View::Pop()//出栈函数
{
//弹出栈顶元素
Stack_node *t;
Base=Head;
if(Base->NextNULL)
{
Head=NULL;
return Base;
}
while(Base->Next!=NULL)
{
Base=Base->Next;
if(Base->Next
Last)
{
Base->Next=NULL;
t = Last;
Last = Base;
return t;
}
}
return NULL;
}
实验作业:

  1. 完成四连通种子填充函数PolygonFill(),提示:边界点颜色为黑色,在OnDraw()函数中,填充之前用黑色线条绘制出多边形。
    代码:
void CSeedFillingView::OnDraw(CDC* pdc)
{
	CSeedFillingDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;
	 Point[0] = CPoint(20,20);
	 Point[1] = CPoint(20,300);
	 Point[2] = CPoint(60,60);
	 Point[3] = CPoint(300,20);
	 Head = Last = NULL;
	 COLORREF fillColor=RGB(0,255,0);
	 COLORREF boundaryColor=RGB(255,255,255);
	 Seed=CPoint(40,40);
	 pdc->Polygon(Point,4);	
	 PolygonFill(Seed,fillColor,boundaryColor);
	// TODO: 在此处为本机数据添加绘制代码
}


2. 在OnDraw()函数中,用黑色的线条绘制出多边形,设置一个内部点作为种子点,调用PolygonFill()进行填充。
代码:
这里一开始用了老师的进栈出栈大函数,花费了好久个小时,都没有做成功,检查许久还没有发现,后面利用C++里面的库函数stack。
需要在SeedFillingView.h加上
#include<stack>
using namespace std;
就可以了。
在SeedFillingView.cpp中:
void CSeedFillingView::PolygonFill(CPoint Seed,COLORREF fillColor,COLORREF boundaryColor)//区域填充
{
	CClientDC *pdc;
	pdc=new CClientDC(this);
	CPoint head;
	head=Seed;
	stack<CPoint> s;
	s.push(head);
	while (!s.empty())
	{
		
		CPoint base=s.top();//访问栈顶
		s.pop();//栈顶元素出栈
		pdc->SetPixel(base,fillColor);
		
				PointTop.x=base.x;	//(x, y+1)
		        PointTop.y=base.y+1;	//(x, y+1)
				
				if (pdc->GetPixel(PointTop)== boundaryColor&&pdc->GetPixel(PointTop)!=fillColor)
			{
				s.push(PointTop);
			}
				PointLeft.x=base.x-1;//(x-1, y)
				PointLeft.y=base.y;//(x-1, y)
				if (pdc->GetPixel(PointLeft)== boundaryColor&&pdc->GetPixel(PointLeft)!=fillColor)
			{
				s.push(PointLeft);
			}
				PointBottom.x=base.x;//(x, y-1)
				PointBottom.y=base.y-1;//(x, y-1)
				if (pdc->GetPixel(PointBottom)== boundaryColor&&pdc->GetPixel(PointBottom)!=fillColor)
			{
				s.push((PointBottom));
			}
				PointRight.x=base.x+1;//(x+1, y)
				PointRight.y=base.y;//(x+1, y)
				if (pdc->GetPixel(PointRight)== boundaryColor&&pdc->GetPixel(PointRight)!=fillColor)
			{
				s.push(PointRight);
				
			}
				
	}

老师给的答案:

void CTestView::PolygonFill()//区域填充函数

{

	CClientDC dc(this);

	COLORREF FillColor,BoundaryColor,PixelColor;//填充色,边界色,当前点像素色

	BoundaryColor=RGB(0,0,0);//边界色为黑色

	FillColor=RGB(0,0,255);//填充色为蓝色

	Head=new Stack_node();//建立堆栈结点

	Head->PixelPoint=Seed;//种子结点入栈

	Head->Next=NULL;

	while(Head!=NULL)//如果栈不为空

	{	

		Stack_node *PopPoint;

		PopPoint=Pop();

		if(PopPoint==NULL)	

			return;

		//Last=Base;

		dc.SetPixel(PopPoint->PixelPoint,FillColor);//画蓝色种子

		//搜索出栈结点的左方像素

		PointLeft.x=PopPoint->PixelPoint.x-1;

		PointLeft.y=PopPoint->PixelPoint.y;

		PixelColor=dc.GetPixel(PointLeft.x,PointLeft.y);

		if(PixelColor!=BoundaryColor && PixelColor!=FillColor)

		//不是边界色并且未置成填充色	

			Push(PointLeft);//左方像素入栈

		//搜索出栈结点的上方像素

		PointTop.x=PopPoint->PixelPoint.x;

		PointTop.y=PopPoint->PixelPoint.y+1;

		PixelColor=dc.GetPixel(PointTop);

		if(PixelColor!=BoundaryColor && PixelColor!=FillColor)

			Push(PointTop);	//上方像素入栈

		//搜索出栈结点的右方像素

		PointRight.x=PopPoint->PixelPoint.x+1;

		PointRight.y=PopPoint->PixelPoint.y;

		PixelColor=dc.GetPixel(PointRight);

		if(PixelColor!=BoundaryColor && PixelColor!=FillColor)

			Push(PointRight);//右方像素入栈

		//搜索出栈结点的下方像素

		PointBottom.x=PopPoint->PixelPoint.x;

		PointBottom.y=PopPoint->PixelPoint.y-1;

		PixelColor=dc.GetPixel(PointBottom);

		if(PixelColor!=BoundaryColor && PixelColor!=FillColor)

			Push(PointBottom);//下方像素入栈

	}

}

截图:
在这里插入图片描述

种子填充算法,自己写的,希望对大家有用 // 种子法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
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值