图像多边形填充算法

算法原理:
参考连接:http://alienryderflex.com/polygon/,这里介绍得很详细,但是参考其中代码,实现下来,发现其中有一个bug,不知道是不是我自己的问题。
多边形绘制在原始图上:
这里写图片描述
为了高效,先确定多边形的坐标范围:

typedef struct boundary_t
{
    int left;
    int right;
    int top;
    int bottom;
}bound;

typedef struct loc_t
{
    int x;
    int y;
}loc;

void get_polygon_boundary(loc* poly, int count, bound* b)
{
    if (!b)return;
    int left, top, right, bottom;
    left = top = INT_MAX;
    right = bottom = INT_MIN;
    int i;
    loc pos;
    for (i = 0; i < count; i++)
    {
        pos = poly[i];
        if (pos.x < left)left = pos.x;
        if (pos.y < top)top = pos.y;
        if (pos.x > right)right = pos.x;
        if (pos.y > bottom)bottom = pos.y;
    }
    b->left = left;
    b->right = right;
    b->top = top;
    b->bottom = bottom;
}

这里所使用的多边形顶点,全部归一化到(0,1):

#define POLYGON_NODE_NUM 6
//多边形顶点
float polygon[POLYGON_NODE_NUM][2] =
{
    {
        0.15000000596046448,
        0.28727272152900696
    },
    {
        0.22857142984867096,
        0.7236363887786865
    },
    {
        0.22857142984867096,
        0.7236363887786865
    },
    {
        0.6471428275108337,
        0.8054545521736145
    },
    {
        0.6471428275108337,
        0.8054545521736145
    },
    { 
        0.7814285755157471, 
        0.0672727301716804 
    }
};

上面链接中判断点是否在多边形内的方法:

bool point_in_polygon(loc* poly, int count, loc pos)
{   
    int   i, j = count - 1;
    bool  oddNodes = false;
    int x, y;

    x = pos.x, y = pos.y;
    for (i = 0; i < count; i++) 
    {
        if ((poly[i].y < y && poly[j].y >= y|| poly[j].y < y && poly[i].y >= y)
            && (poly[i].x <= x || poly[j].x <= x)) 
        {
            oddNodes ^= (poly[i].x + (y - poly[i].y) / (poly[j].y - poly[i].y)*(poly[j].x - poly[i].x) < x);
        }
        j = i;
    }

    return oddNodes;
}

截取的多边形:
这里写图片描述,对比一下图一中的多边形框和此图,明显存在问题。

因此,又搜索了一把, 在其他地方找的判断方法:

int lineIntersect(float v1x1, float v1y1, float v1x2, float v1y2,float v2x1, float v2y1, float v2x2, float v2y2) 
{
    float d1, d2;
    float a1, a2, b1, b2, c1, c2;

    // Convert vector 1 to a line (line 1) of infinite length.
    // We want the line in linear equation standard form: A*x + B*y + C = 0
    // See: http://en.wikipedia.org/wiki/Linear_equation
    a1 = v1y2 - v1y1;
    b1 = v1x1 - v1x2;
    c1 = (v1x2 * v1y1) - (v1x1 * v1y2);

    // Every point (x,y), that solves the equation above, is on the line,
    // every point that does not solve it, is not. The equation will have a
    // positive result if it is on one side of the line and a negative one 
    // if is on the other side of it. We insert (x1,y1) and (x2,y2) of vector
    // 2 into the equation above.
    d1 = (a1 * v2x1) + (b1 * v2y1) + c1;
    d2 = (a1 * v2x2) + (b1 * v2y2) + c1;

    // If d1 and d2 both have the same sign, they are both on the same side
    // of our line 1 and in that case no intersection is possible. Careful, 
    // 0 is a special case, that's why we don't test ">=" and "<=", 
    // but "<" and ">".
    if (d1 > 0 && d2 > 0) return NO;
    if (d1 < 0 && d2 < 0) return NO;
    // The fact that vector 2 intersected the infinite line 1 above doesn't 
    // mean it also intersects the vector 1. Vector 1 is only a subset of that
    // infinite line 1, so it may have intersected that line before the vector
    // started or after it ended. To know for sure, we have to repeat the
    // the same test the other way round. We start by calculating the 
    // infinite line 2 in linear equation standard form.
    a2 = v2y2 - v2y1;
    b2 = v2x1 - v2x2;
    c2 = (v2x2 * v2y1) - (v2x1 * v2y2);

    // Calculate d1 and d2 again, this time using points of vector 1.
    d1 = (a2 * v1x1) + (b2 * v1y1) + c2;
    d2 = (a2 * v1x2) + (b2 * v1y2) + c2;

    // Again, if both have the same sign (and neither one is 0),
    // no intersection is possible.
    if (d1 > 0 && d2 > 0) return NO;
    if (d1 < 0 && d2 < 0) return NO;

    // If we get here, only two possibilities are left. Either the two
    // vectors intersect in exactly one point or they are collinear, which
    // means they intersect in any number of points from zero to infinite.
    if ((a1 * b2) - (a2 * b1) == 0.0f) return COLLINEAR;

    // If they are not collinear, they must intersect in exactly one point.
    return YES;
}

bool point_in_polygon_with_bound(loc* poly, int count, loc pos, bound b)
{
    int   i, j = count - 1;
    bool  oddNodes = false;
    int x0, y0;
    int x1, y1;
    x0 = pos.x, y0 = pos.y;

    x1 = b.left - 1;
    y1 = y0;
    for (i = 0; i < count; i++)
    {
        if ((poly[i].y < y0 && poly[j].y >= y0 || poly[j].y < y0 && poly[i].y >= y0)
            && (poly[i].x <= x0 || poly[j].x <= x0))
        {
            if (areIntersecting(x0, y0, x1, y1, poly[i].x, poly[i].y, poly[j].x, poly[j].y) == YES)
            {
                oddNodes = !oddNodes;
            }
        }
        j = i;
    }
    return oddNodes;
}

注意,共线的情况下是要去除的。如果扫描直线穿过多边形的顶点,相当于相交两条直线,不影响判断结果。

最终效果:

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
#include<windows.h> #include<GL/gl.h> #include<GL/glu.h> #include<GL/glaux.h> #pragma comment(lib,"opengl32") #pragma comment(lib,"glu32") #pragma comment(lib,"glaux") void Init(void); void CALLBACK Display(void); void Init(void) { //clear background to black glClearColor(1.0,1.0,1.0,0.0); glShadeModel(GL_FLAT); } void CALLBACK Display(void) { //定义32*32的位图数据 GLubyte fly[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x03,0x08,0x01,0xc0,0x06,0xc0,0x03,0x60 ,0x04,0x60,0x06,0x20,0x04,0x30,0x0c,0x20 ,0x04,0x18,0x18,0x20,0x04,0x0c,0x30,0x20 ,0x04,0x06,0x60,0x20,0x44,0x03,0xc0,0x22 ,0x44,0x01,0x80,0x22,0x44,0x01,0x80,0x22 ,0x44,0x01,0x80,0x22,0x44,0x01,0x80,0x22 ,0x44,0x01,0x80,0x22,0x44,0x01,0x80,0x22 ,0x66,0x01,0x80,0x66,0x33,0x01,0x80,0xcc ,0x19,0x81,0x81,0x98,0x0c,0xc1,0x83,0x30 ,0x07,0xe1,0x87,0xe0,0x03,0x3f,0xfc,0xc0 ,0x03,0x31,0x8c,0xc0,0x03,0x33,0xcc,0xc0 ,0x06,0x64,0x26,0x60,0x0c,0xcc,0x33,0x30 ,0x18,0xcc,0x33,0x18,0x10,0xc4,0x23,0x08 ,0x10,0x63,0xc6,0x08,0x10,0x30,0x0c,0x08 ,0x10,0x18,0x18,0x08,0x10,0x00,0x00,0x08 }; GLubyte half[]={0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55 ,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55 ,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55 ,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55 ,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55 ,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55 ,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55 ,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55 ,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55 ,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55 ,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55 ,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55 ,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55 ,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55 ,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55 ,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55 }; glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.0,0.0,0.0); //绘制一个纯黑的矩形 glRectf(25.0,25.0,125.0,125.0);
#include #include #include #include #include //////////////////////////////////////////////////////////////functions///////////////////////////////////////////////// void swap(float &m,float &n) { float temp=n; n=m; m=temp; } int sign(float a,float b)//sign() { int t; if(a>b) { t=1;} else if(adx) { swap(dx,dy); Flag=1; } else Flag=0; float Nerror=2*dy-dx; for(int i=1;i=0) { if(Flag) { x=x+sx;} else y=y+sy; Nerror=Nerror-2*dx; } if(Flag) { y=y+sy;} else x=x+sx; Nerror=Nerror+2*dy; } } ///////////////////////////////////四连通种子填充/////////////////////////////////////////////////// void BoundaryFill4(HDC hdc,int x,int y,int FilledColor,int BoundaryColor) { int CurrentColor; CurrentColor=GetPixel(hdc,x,y); if(CurrentColor!=BoundaryColor&&CurrentColor!=FilledColor) { SetPixel(hdc,x,y,FilledColor); BoundaryFill4(hdc,x+1,y,FilledColor,BoundaryColor); BoundaryFill4(hdc,x-1,y,FilledColor,BoundaryColor); BoundaryFill4(hdc,x,y+1,FilledColor,BoundaryColor); BoundaryFill4(hdc,x,y-1,FilledColor,BoundaryColor); } } ////////////////////////////////////////扫描线填充/////////////////////////////////////////////////// //DrawLine()函数:在(x1,y)和(x2,y)两点之间画一条颜色为FilledColor的横线(用来扫描填充) void drawline(HDC hdc, int x1, int x2,int y0, int FilledColor) { for(int n=x1+1;n<x2;n++) { SetPixel(hdc,n,y0,FilledColor); } } //Scan()函数:扫描线函数,将扫描线与图形的交点坐标存在数组中 //数组中同行的点即为该行扫描线与图形的交点(一般为2个) //数组中的行代表扫描线的纵坐标 void scan(HDC hdc, int boundarycolor) { int currentcolor; int a[300][2]={0}; for (int j=0;j<300;j++) { for(int i=300;i<700;i++) { currentcolor=GetPixel(hdc,i,j); if((currentcolor==boundarycolor)&&(GetPixel(hdc,i+1,j)!=boundarycolor)&&(i500)) {a[j][1]=i;} } } //利用循环调用DrawLine函数逐行填充两交点之间的点 for(int k=0;k<300;k++) { if((a[k][0]!=0)&&(a[k][1]!=0)) drawline(hdc,a[k][0],a[k][1],k,RGB(255,0,0));} } ///////////////////////////////////////////////边界填充////////////////////////////////////// //Contrary()取反函数:如果点的颜色为白,则将点置为填充色;如果点的颜色为填充色,则将点置为白色 //忽略了边界色,即不对边界点作颜色处理 void contrary(HDC hdc, int x, int y,int FilledColor) { for(int h=x;h<280;h++) { if(GetPixel(hdc,h,y)==RGB(255,255,255)) { SetPixel(hdc,h,y,FilledColor); } else if(GetPixel(hdc,h,y)==FilledColor) { SetPixel(hdc,h,y,RGB(255,255,255)); } } } //borderline()边线函数: 先找出图形的边界 左边和右边,从右到左的顺序调用contrary()函数进行填充 void borderline(HDC hdc, int boundarycolor) { for(int j=280;j<499;j++) { for(int i=80;i100)) { contrary(hdc,i,j,RGB(0,0,255)); } } } for(int m=280;m<499;m++) { for(int n=80;n<280;n++) { int currentcolor=GetPixel(hdc,n,m); if((currentcolor==boundarycolor)&&(GetPixel(hdc,n+1,m)!=boundarycolor)&&(GetPixel(hdc,n-1,m)!=boundarycolor)&&(n<101)) { contrary(hdc,n,m,RGB(0,0,255)); } } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值