2017-09-04 1 views
0

Ich arbeite an der Begradigung von Splines als Teil meines größeren Projekts, um gekrümmten Text zu begradigen.Begradigen Sie einen Spline mithilfe von Derivaten, um die Rotation an jedem Punkt zu bestimmen.

Nach dem Anpassen eines Splines an meine Datenpunkte verwende ich scipy splev, um die Ableitung des Splines an jedem Punkt entlang der Kurve zu erhalten. Da die Ableitung mir die Neigung der Tangente zur Kurve an einem gegebenen Punkt gibt (wenn ich nicht sehr verwirrt bin), bestimmt ich die Drehung, die benötigt wird, um eine gerade Linie zu erzeugen, indem ich die Ableitung mit einer Linie mit Steigung 0 vergleiche.

Nachdem ich die Rotation an jedem Punkt festgelegt habe, um meinen Spline zu richten, schleife ich über jeden Punkt und setze die korrigierende Drehung auf den aktuellen Punkt und jeden vorhergehenden Punkt.

Der entsprechende Code folgt:

import numpy as np 
from numpy import arange 
from scipy import interpolate 
import matplotlib.pyplot as plt 
import math 
import random 

def rotate(origin, point, angle): 

    ox, oy = origin 
    px, py = point 

    qx = ox + math.cos(angle) * (px - ox) - math.sin(angle) * (py - oy) 
    qy = oy + math.sin(angle) * (px - ox) + math.cos(angle) * (py - oy) 

    return qx, qy 

xxx = [0,2,4,4,2,0] 
yyy = [0,2,4,6,8,10] 

tckp, u = interpolate.splprep([xxx, yyy], s=3, k=2, nest=-1) 

xpointsnew, ypointsnew = interpolate.splev(u, tckp) 

dx, dy = interpolate.splev(u, tckp, der=1) 
fullder = dy/dx 

rotating_x = xxx 
rotating_y = yyy 
index = -1 
for i in fullder: 
    index += 1 
    corrective_rotation = -(math.degrees(math.atan(0)-math.atan(fullder[index]))) 
    print(corrective_rotation) 
    rotation_center = [rotating_x[index], rotating_y[index]] 
    target_indices = np.arange(0,index,1) 
    for i in target_indices: 
     rotation_target = [rotating_x[i], rotating_y[i]] 
     qx, qy = rotate(rotation_target,rotation_center,math.radians(corrective_rotation)) 
     rotating_x[i] = qx 
     rotating_y[i] = qy 

print(rotating_x) 
print(rotating_y) 

plt.plot(xpointsnew, ypointsnew, 'r-') 
plt.plot(rotating_x, rotating_y, 'b-') 
plt.show() 

Was ich tue, nicht funktioniert, aber ich bin mir nicht sicher, warum. Die resultierende Linie ist nicht nur gerade, sondern auch viel kürzer als die ursprüngliche Kurve. Ist der oben skizzierte Ansatz in irgendeiner Weise grundlegend fehlerhaft? Mache ich etwas Dummes in meinem Code? Ich würde wirklich ein zweites Augenpaar schätzen.

+0

Sie definieren rotate-Methode und Sie verwenden es überhaupt nicht. – MishaVacic

+0

@MishaVacic Ich nicht? Ich bin mir ziemlich sicher, dass ich hier mache: 'qx, qy = rotiere (rotation_target, rotation_center, math.radians (corrective_rotation))' – Tric

Antwort

0

Ein grundlegender Fehler des Algorithmus besteht darin, dass er die Steigung an einem Punkt als die Menge an notwendiger Drehung eines von zwei Segmenten annimmt, in der dieser Punkt die Kurve teilt. Betrachten Sie als Beispiel eine gerade Linie bei 60 Grad. Ihr Algorithmus erzeugt an jedem Knoten der Linie eine Drehung von 60 Grad, wodurch alle Winkel von 120 Grad erreicht werden.

Sie drehen nicht die gesamte Kurve, nur ein Teil davon (bis zu index in Ihrer Version; nach i in meiner Version). Die geeignete Menge an Rotation ist, wie stark sich die Kurve an diesem Punkt dreht, was sich in der Änderung ihrer Steigung widerspiegelt, die nicht die Steigung selbst ist.

Dann gibt es kleine Details wie

  • falsche Reihenfolge der rotation_center und rotation_target in der Liste der Argumente;
  • sinnlose Umwandlung in Grad und zurück;
  • mit atan(dy/dx), wobei atan2(dy, dx) verwendet werden sollte;
  • und die seltsame Entscheidung, vom Ende der Kurve zu drehen.

Hier ist meine Version; Die einzigen Änderungen sind in der for-Schleife.

for i in range(len(xxx)-1): 
    corrective_rotation = -(math.atan2(dy[i+1], dx[i+1]) - math.atan2(dy[i], dx[i])) 
    print(corrective_rotation) 
    rotation_center = [rotating_x[i], rotating_y[i]] 
    for k in range(i+1, len(xxx)): 
     rotation_target = [rotating_x[k], rotating_y[k]] 
     qx, qy = rotate(rotation_center, rotation_target, corrective_rotation) 
     rotating_x[k] = qx 
     rotating_y[k] = qy 

straightened

By the way, plt.axes().set_aspect('equal') hilft, die Illusion zu vermeiden, dass die Kurvenlänge nach der Drehung verändert.

Schließlich sollte ich sagen, dass die Annahme von Winkeln aus den Punktwerten der Ableitung eines interpolierenden Splines eine sehr fragwürdige Entscheidung ist. Finite Unterschiede in einem angemessenen Maßstab sind robuster.

Verwandte Themen