目录
中点画圆法
算法理论
首先只考虑圆心在原点的第二8分圆。要生成完整的圆可以通过平移、反射变换得到。
当P点坐标
(xp,yp)
(
x
p
,
y
p
)
已确定时,下一像素点只能取
(xp+1,yp)
(
x
p
+
1
,
y
p
)
或
(xp+1,yp−1)
(
x
p
+
1
,
y
p
−
1
)
。
构造误差函数:
对于P的下一像素中点M,有 M(xp+1,yp−0.5) M ( x p + 1 , y p − 0.5 )
∴F(M)=(xp+1)2+(yp−0.5)2−R2 ∴ F ( M ) = ( x p + 1 ) 2 + ( y p − 0.5 ) 2 − R 2
以 d d 表示误差值,由于P点起始位置取(0,R),则初值为:
算法实现
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=d−0.25=1−r 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;
}
}
}
中点画椭圆算法
算法理论
中点画椭圆算法与重点画圆算法类似,确定一个像素后,再在两个候选像素之间的中点计算判别式,再确定选哪个点。
根据椭圆方程:
对于p点的下一中点:
算法实现
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--;
}
}
}