Back to Home

Thuật toán tự khớp đường cong - P.J. Schneider

Thuật toán của Philip J. Schneider, công bố lần đầu trong cuốn Graphics Gems I (1990), là một giải pháp thích nghi (adaptive) giúp biến một tập hợp các điểm số hóa rời rạc PiP_i thành một chuỗi các đoạn đường cong Bézier bậc ba mượt mà.

Link của bài báo tại đây.

Điểm đặc biệt của thuật toán này là việc đảm bảo tính liên tục hình học G1G^1, cho phép đường cong linh hoạt hơn so với liên tục tham số C1C^1 truyền thống.

1. Cơ sở Toán học: Đường cong Bézier bậc ba

Một đoạn Bézier bậc ba được định nghĩa bởi 4 điểm điều khiển V0,V1,V2,V3V_0, V_1, V_2, V_3. Công thức tổng quát là:

Q(t)=i=03ViBi3(t),t[0,1]Q(t) = \sum_{i=0}^{3} V_i B_i^3(t), \quad t \in [0, 1]

Trong đó Bi3(t)B_i^3(t) là các đa thức Bernstein bậc ba:

  • B03(t)=(1t)3B_0^3(t) = (1-t)^3

  • B13(t)=3t(1t)2B_1^3(t) = 3t(1-t)^2

  • B23(t)=3t2(1t)B_2^3(t) = 3t^2(1-t)

  • B33(t)=t3B_3^3(t) = t^3

Ứng với một giá trị tt cụ thể trong đoạn [0,1][0,1] sẽ là một điểm trên đường cong.

2. Tính liên tục: C1C^1G1G^1 Continuity

Trong thiết kế đường cong piecewise (nối từ nhiều đoạn), việc làm thế nào để các khớp nối trông "mượt mà" là cực kỳ quan trọng. Schneider nhấn mạnh việc sử dụng G1G^1 thay vì C1C^1.

2.1. Liên tục tham số (C1C^1 - Parametric Continuity)

Một khớp nối giữa hai đoạn đường cong được gọi là C1C^1 nếu đạo hàm bậc nhất của chúng tại điểm nối là hoàn toàn bằng nhau về cả hướngđộ lớn.

  • Điều kiện: Q1(1)=Q2(0)Q_1'(1) = Q_2'(0).

  • Ý nghĩa hình học: Nếu bạn coi đường cong là quỹ đạo của một hạt đang di chuyển, C1C^1 yêu cầu hạt đó phải đi qua khớp nối với vận tốc không đổi (không tăng tốc hay giảm tốc đột ngột).

  • Hạn chế: Trong khớp đường cong (curve fitting), điều này quá cứng nhắc. Nó bắt buộc các điểm điều khiển V1,V2V_1, V_2 phải cách điểm mút một khoảng cố định bằng nhau ở cả hai phía.

2.2. Liên tục hình học (G1G^1 - Geometric Continuity)

Một khớp nối là G1G^1 nếu các vector đạo hàm bậc nhất tại điểm nối có cùng hướng nhưng có thể khác nhau về độ lớn.

  • Điều kiện: Q1(1)=kQ2(0)Q_1'(1) = k \cdot Q_2'(0) với k>0k > 0.

  • Ý nghĩa hình học: Các vector tiếp tuyến chỉ cần nằm trên cùng một đường thẳng (collinear). Hạt di chuyển có thể tăng hoặc giảm tốc khi đi qua khớp nối, miễn là nó không thay đổi hướng đột ngột.

  • Lợi ích trong thuật toán Schneider: G1G^1 giải phóng các tham số α1,α2\alpha_1, \alpha_2 (độ dài vector tiếp tuyến). Việc cho phép α\alpha thay đổi độc lập giúp đường cong có thêm "tự do" để áp sát vào các điểm dữ liệu thực tế mà vẫn đảm bảo vẻ ngoài mượt mà.

3. Các bước chính của thuật toán

Mục tiêu bài toán:

Cho tập điểm P0,P1,,PnP_0,P_1,\dots,P_n, mục tiêu là tìm một hoặc một số các đường cong nối liền nhau sao cho các đường cong này khớp (bestfit) với tập điểm đã cho.

Bước 1: Tham số hóa ban đầu (Chord-Length Parameterization)

Để khớp đường cong, ta cần biết mỗi điểm dữ liệu PiP_i tương ứng với giá trị tt nào trên đoạn [0,1][0, 1]. Vì chưa có đường cong, ta ước tính tit_i dựa trên khoảng cách giữa các điểm (độ dài dây cung hay ở đây là Chord-Length). Nghĩa là chiều dài từ điểm P0P_0 đến PiP_i, được tính bằng tổng khoảng cách các đoạn thẳng P0P1,P1P2,,Pi1PiP_0P_1,P_1P_2,\dots,P_{i-1}P_i và chuẩn hóa bằng cách chia cho tổng chiều dài các đoạn thẳng. Cụ thể, theo bài báo:

u0=0ui=ui1+PiPi1u_0 =0 \\ u_i = u_{i-1} + |P_i - P_{i-1}|

Sau đó chuẩn hóa ti=ui/un1t_i = u_i / u_{n-1} để t[0,1]t \in [0, 1].

Bước 2: Ràng buộc Tiếp tuyến và Alpha

Để đảm bảo tính mượt mà tại các khớp nối, hai điểm điều khiển bên trong (V1,V2V_1, V_2) phải nằm trên hướng tiếp tuyến đơn vị t^1\hat{t}_1t^2\hat{t}_2 tại hai đầu mút (V0,V3V_0, V_3):

  • V1=V0+α1t^1V_1 = V_0 + \alpha_1 \hat{t}_1

  • V2=V3+α2t^2V_2 = V_3 + \alpha_2 \hat{t}_2

Bài toán lúc này trở thành: Tìm α1,α2\alpha_1, \alpha_2 để cực tiểu hóa sai số bình phương.

Bước 3: Giải Alpha bằng Phương pháp Bình phương tối thiểu (Least Squares)

Ta cần tối thiểu hóa hàm mục tiêu SS:

S=i=1nPiQ(ti)2S = \sum_{i=1}^{n} |P_i - Q(t_i)|^2

Nghĩa là ở bước này, chúng ta phải tìm α1,α2\alpha_1, \alpha_2 để hàm SS đạt cực tiểu. Tại điểm cực tiểu, đạo hàm riêng theo α1,α2\alpha_1, \alpha_2 phải bằng 00.

Sα1=0,Sα2=0\frac{\partial S}{\partial \alpha_1} = 0, \frac{\partial S}{\partial \alpha_2} = 0

Đây thực chất có thể hình dung như việc di dời các điểm control points của đường cong trên trục là các vector t1^,t2^\hat{t_1}, \hat{t_2} sao cho tổng khoảng cách các điểm PiP_i đến đường cong là nhỏ nhất.

Để giải được α\alpha, trước tiên ta thay thế ràng buộc tiếp tuyến vào phương trình Bézier:
V1=V0+α1t^1V_1 = V_0 + \alpha_1 \hat{t}_1
V2=V3+α2t^2V_2 = V_3 + \alpha_2 \hat{t}_2

Thay vào Q(t)Q(t):

Q(t)=V0B03(t)+(V0+α1t^1)B13(t)+(V3+α2t^2)B23(t)+V3B33(t)Q(t) = V_0 B_0^3(t) + (V_0 + \alpha_1 \hat{t}_1) B_1^3(t) + (V_3 + \alpha_2 \hat{t}_2) B_2^3(t) + V_3 B_3^3(t)

Bây giờ, ta nhóm các thành phần đã biết (hằng số)chưa biết (α\alpha):

Q(t)=[V0B03(t)+V0B13(t)+V3B23(t)+V3B33(t)]ConstantPart(t)+α1[t^1B13(t)]A1(t)+α2[t^2B23(t)]A2(t)Q(t) = \underbrace{\left[ V_0 B_0^3(t) + V_0 B_1^3(t) + V_3 B_2^3(t) + V_3 B_3^3(t) \right]}_{\text{ConstantPart}(t)} + \alpha_1 \underbrace{[\hat{t}_1 B_1^3(t)]}_{A_1(t)} + \alpha_2 \underbrace{[\hat{t}_2 B_2^3(t)]}_{A_2(t)}

Đặt:

  • f(t)=ConstantPart(t)f(t) = \text{ConstantPart}(t)

  • A1(t)=t^1B13(t)A_1(t) = \hat{t}_1 B_1^3(t)

  • A2(t)=t^2B23(t)A_2(t) = \hat{t}_2 B_2^3(t)

Vậy: Q(t)=f(t)+α1A1(t)+α2A2(t)Q(t) = f(t) + \alpha_1 A_1(t) + \alpha_2 A_2(t)

Triển khai đạo hàm

Hàm sai số: S=i=0nPiQ(ti)2S = \sum_{i=0}^{n} |P_i - Q(t_i)|^2

Đạo hàm theo α1\alpha_1:

Sα1=2(PiQ(ti))(Q(ti)α1)=0\frac{\partial S}{\partial \alpha_1} = \sum 2(P_i - Q(t_i)) \cdot \left( -\frac{\partial Q(t_i)}{\partial \alpha_1} \right) = 0

Khai triển và chuyển vế:

α1(A1(ti)A1(ti))C11+α2(A2(ti)A1(ti))C12=(Pif(ti))A1(ti)X1\alpha_1 \underbrace{\sum (A_1(t_i) \cdot A_1(t_i))}_{C_{11}} + \underbrace{\alpha_2 \sum (A_2(t_i) \cdot A_1(t_i))}_{C_{12}} = \underbrace{\sum (P_i - f(t_i)) \cdot A_1(t_i)}_{X_1}

Tương tự cho α2\alpha_2, ta có hệ phương trình:

{C11α1+C12α2=X1C21α1+C22α2=X2\begin{cases} C_{11}\alpha_1 + C_{12}\alpha_2 = X_1 \\ C_{21}\alpha_1 + C_{22}\alpha_2 = X_2 \end{cases}

Cụ thể, X1X_1X2X_2 đại diện cho phần sai số còn dư mà các điểm mút cố định không thể khớp được, được chiếu lên các hướng tiếp tuyến:

X1=i=0n[Pi(V0B03(ti)+V0B13(ti)+V3B23(ti)+V3B33(ti))](t^1B13(ti))X2=i=0n[Pi(V0B03(ti)+V0B13(ti)+V3B23(ti)+V3B33(ti))](t^2B23(ti))X_1 = \sum_{i=0}^{n} \left[ P_i - \left( V_0 B_0^3(t_i) + V_0 B_1^3(t_i) + V_3 B_2^3(t_i) + V_3 B_3^3(t_i) \right) \right] \cdot (\hat{t}_1 B_1^3(t_i)) \\ X_2 = \sum_{i=0}^{n} \left[ P_i - \left( V_0 B_0^3(t_i) + V_0 B_1^3(t_i) + V_3 B_2^3(t_i) + V_3 B_3^3(t_i) \right) \right] \cdot (\hat{t}_2 B_2^3(t_i))

Ý nghĩa hình học :
(Pif(ti))(P_i - f(t_i)) là vector nối từ "đường cong hằng số" (đường cong khi α=0\alpha=0) đến điểm dữ liệu thực tế. X1,X2X_1, X_2 là tổng các hình chiếu của các vector sai số này lên hướng của tiếp tuyến đầu mút, trọng số bởi đa thức Bernstein.

Bước 4: Tinh chỉnh Tham số (Newton-Raphson Iteration)

Sau khi có đường cong tạm thời, các giá trị tit_i ban đầu (tính theo dây cung) thường không phải là vị trí tối ưu nhất. Ta cần tìm tit_i mới sao cho điểm Q(ti)Q(t_i)hình chiếu vuông góc của PiP_i lên đường cong.

Ta giải phương trình vuông góc: f(t)=[Q(t)Pi]Q(t)=0f(t) = [Q(t) - P_i] \cdot Q'(t) = 0.
Sử dụng phương pháp Newton-Raphson:

tnew=tf(t)f(t)=t[Q(t)Pi]Q(t)Q(t)2+[Q(t)Pi]Q(t)t_{new} = t - \frac{f(t)}{f'(t)} = t - \frac{[Q(t) - P_i] \cdot Q'(t)}{|Q'(t)|^2 + [Q(t) - P_i] \cdot Q''(t)}

Việc lặp lại quá trình này (khoảng 4-5 lần) giúp đường cong "hút" sát vào các điểm dữ liệu một cách đáng kể.

Bước 5: Chia tách đệ quy (G1G^1 Continuity)

Khi sai số vượt ngưỡng, ta chia đôi tại điểm lỗi nhất, tạm gọi là PkP_k. Vector tiếp tuyến chung T\vec{T} tại điểm chia PkP_k được tính:

T=Normalize(Pk+1Pk1)\vec{T} = \text{Normalize}(P_{k+1} - P_{k-1})
  • Đoạn trái dùng t^2=T\hat{t}_2 = -\vec{T}.

  • Đoạn phải dùng t^1=T\hat{t}_1 = \vec{T}.

Sau đó lại áp dụng fitting curve cho 2 nửa P0,P1,,PkP_0,P_1,\dots,P_kPk,Pk+1,,PnP_k,P_{k+1},\dots,P_n

Demo

Comments

0/300

Leave name/email blank to comment anonymously

No comments yet. Be the first to comment!