圆与椭圆的直线扫描算法

目录

中点画圆法

算法理论

首先只考虑圆心在原点的第二8分圆。要生成完整的圆可以通过平移、反射变换得到。
当P点坐标 (xp,yp) ( x p , y p ) 已确定时,下一像素点只能取 (xp+1,yp) ( x p + 1 , y p ) (xp+1,yp1) ( x p + 1 , y p − 1 )
构造误差函数:

F(x,y)=x2+y2R2 F ( x , y ) = x 2 + y 2 − R 2
当点在圆内时, F(x,y)<0 F ( x , y ) < 0
对于P的下一像素中点M,有 M(xp+1,yp0.5) M ( x p + 1 , y p − 0.5 )
F(M)=(xp+1)2+(yp0.5)2R2 ∴ F ( M ) = ( x p + 1 ) 2 + ( y p − 0.5 ) 2 − R 2
d d 表示误差值,由于P点起始位置取(0,R),则初值为:
d0=1+(R0.5)2R2=1.25R
若取正右方一点,则下一判别点:
d=F(xp+2,yp0.5)=d+2xp+3 d = F ( x p + 2 , y p − 0.5 ) = d + 2 x p + 3
若取右下方一点,则下一判别点:
d=F(xp+2,yp1.5)=d+2xp+3+(2yp+2) d = F ( x p + 2 , y p − 1.5 ) = d + 2 x p + 3 + ( − 2 y p + 2 )

算法实现

void MidpointCircle(Mat& m, int r, const Vec3b v){
    double d=1.25-r;
    int x, y;
    for (x = 0, y = r; x<y; x++){
        m.at<Vec3b>(y, x) = v;
        if (d < 0){
            d += 2 * x + 3;
        }
        else{
            d += 2 * (x - y) + 5;
            y--;
        }
    }
}

还可使用 e=d0.25=1r e = d − 0.25 = 1 − r ,判断 d<0 d < 0 转化为 e<0.25 e < − 0.25 e<0 e < 0 。还有更进一步的改进算法,不再详述。

Bresenham画圆算法

算法理论

当以顺时针方向成圆时,以(0,R)为起点,下一元素只可能取该点的正右方像素、正下方像素与右下方像素,分别记为H、V、D点。
算法首先关注右下方像素。首先通过上述的 F(x,y) F ( x , y ) 方法判断,若D点在圆内,则下一点为D、H中一点。之后再判断 δHD=|F(H)||F(D)| δ H D = | F ( H ) | − | F ( D ) | 的正负值即可判断H、D哪点更接近圆弧。
若D点在圆外,与上述过程类似,下一点为D、V中一点,之后再判断 δDV=|F(D)||F(V)| δ D V = | F ( D ) | − | F ( V ) | 即可确定。具体 δ δ 的计算可以通过讨论圆弧从D、H、V间哪里穿过,使用优化的方法。而 ΔD Δ D 的计算也可以用增量的方法,通过讨论下一点取哪个像素而确定其增量。

算法实现

void BresenhamCircle(Mat& m, int r, const Vec3b v){
    int x, y, delta, delta1, delta2, direction;
    x = 0;
    y = r;
    delta = 2 * (1 - r);
    while (y >= 0){
        m.at<Vec3b>(y, x) = v;
        if (delta < 0){
            delta1 = 2 * (delta + y) + 1;
            if (delta1 <= 0)
                direction = 1;
            else
                direction = 2;
        }
        else if (delta>0){
            delta2 = 2 * (delta - x) - 1;
            if (delta2 <= 0)
                direction = 2;
            else
                direction = 3;
        }
        else
            direction = 2;
        switch (direction){
        case 1:
            x++;
            delta += 2 * x + 1;
            break;
        case 2:
            x++;
            y--;
            delta += 2 * (x - y + 1);
            break;
        case 3:
            y--;
            delta += -2 * y - 1;
            break;
        }
    }
}

中点画椭圆算法

算法理论

中点画椭圆算法与重点画圆算法类似,确定一个像素后,再在两个候选像素之间的中点计算判别式,再确定选哪个点。
根据椭圆方程:

F(x,y)=b2x2+a2y2a2b2 F ( x , y ) = b 2 x 2 + a 2 y 2 − a 2 b 2
可以对各中点进行判别。
对于p点的下一中点:
d1=F(xp+1,yp0.5)=b2(xp+1)2a2(yp0.5)2a2b2 d 1 = F ( x p + 1 , y p − 0.5 ) = b 2 ( x p + 1 ) 2 − a 2 ( y p − 0.5 ) 2 − a 2 b 2
若中点在椭圆内,取正右方元素:
d1=b2(xp+2)2a2(yp0.5)2a2b2=d1+b2(2xp+3) d 1 ′ = b 2 ( x p + 2 ) 2 − a 2 ( y p − 0.5 ) 2 − a 2 b 2 = d 1 + b 2 ( 2 x p + 3 )
若中点在椭圆外,取右下方元素:
d1=b2(xp+2)2a2(yp.5)2a2b2=d1+b2(2xp+3)+(2yp+2) d 1 ′ = b 2 ( x p + 2 ) 2 − a 2 ( y p − .5 ) 2 − a 2 b 2 = d 1 + b 2 ( 2 x p + 3 ) + ( − 2 y p + 2 )
d的初值为:
d10=F(1,b0.5)=b2+a2(b+0.25) d 1 0 = F ( 1 , b − 0.5 ) = b 2 + a 2 ( − b + 0.25 )
还需判断上半部分的中止条件。椭圆上一点的法向量为:
N(x,y)=2b2xi+2a2yj N ( x , y ) = 2 b 2 x i + 2 a 2 y j
当转到下半部分时,判别条件为:
b2(xp+1)<a2(yp0.5) b 2 ( x p + 1 ) < a 2 ( y p − 0.5 )

算法实现

void MidpointEllipse(Mat& m, int a, int b, const Vec3b& v){
    int x, y;
    double d1, d2;
    x = 0;
    y = b;
    d1 = double(b)*b + double(a)*a * (0.25 - b);
    while (double(b)*b*(x + 1) < double(a)*a*(-0.5 + y)){
        m.at<Vec3b>(y, x) = v;
        if (d1 < 0){
            d1 += b*b*(2 * x + 3);
            x++;
        }
        else{
            d1 += b*b*(2 * x + 3) + a*a*(-2 * y + 2);
            x++;
            y--;
        }
    }
    d2 = double(b)*b*(0.5 + x)*(0.5 + x) + double(a)*a*(y - 1)*(y - 1) - double(a)*a*b*b;
    while (y > 0){
        m.at<Vec3b>(y, x) = v;
        if (d2 < 0){
            d2 += b*b*(2 * x + 2) + a*a*(-2 * y + 3);
            x++;
            y--;
        }
        else{
            d2 += a*a*(-2 * y + 3);
            y--;
        }
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值