JGU Logo JGU Logo JGU Logo JGU Logo

Institut für Informatik

Modellierung 1

Michael Wand &
David Hartmann
Wintersemester 21/22

Numpy Katzen

Übungsblatt 1
Letzte Änderung: 05. November 2021, 16:07 Uhr
Bearbeitung bis: Freitag, der 5.11.2021, 15 Uhr




Aufgabe 1: Zuerst Numpy Basics


  1. Erstellen von Tensoren & einfache Rechnungen
    1. Erstellen Sie einen Numpy-Tensor der ersten 1'000'000 Quadratzahlen.
      Doku: np.arange
    2. Erstellen Sie einen zufälligen Tensor der gleichen Größe mit zufälligen Fließkommazahlen zwischen 0 und 1 und sortieren Sie diesen.
      Doku: np.random und ndarray.sort
  2. Broadcasting
    Doku: Broadcasting
    (Ausgesprochen nützliches Werkzeug. Lesen Sie hier ruhig die ganze Doku Seite.)


    1. Erstellen Sie eine Multiplikations/„Ein-Mal-Eins“ Tabelle mithilfe von Broadcasting.
      Das Ergebnis sollte also so aussehen:
       array([[   1,   2,   3,   4,   5,   6,   7,   8,   9,  10],
              [   2,   4,   6,   8,  10,  12,  14,  16,  18,  20],
              [   3,   6,   9,  12,  15,  18,  21,  24,  27,  30],
              [   4,   8,  12,  16,  20,  24,  28,  32,  36,  40],
              [   5,  10,  15,  20,  25,  30,  35,  40,  45,  50],
              [   6,  12,  18,  24,  30,  36,  42,  48,  54,  60],
              [   7,  14,  21,  28,  35,  42,  49,  56,  63,  70],
              [   8,  16,  24,  32,  40,  48,  56,  64,  72,  80],
              [   9,  18,  27,  36,  45,  54,  63,  72,  81,  90],
              [  10,  20,  30,  40,  50,  60,  70,  80,  90, 100]])
      
    2. Erstellen Sie einen zufälligen 2d-Tensor aus \(\{0,1\}^{1000\times 1000}\) und teilen Sie alle Zahlen durch die jeweilige Spaltensumme.
      Verifizieren Sie, dass die Spaltensumme des resultierenden Tensors stets 1 ist.
  3. Reshaping & Indizierung
    Doku: Indizierung
    (Auch hier kann ich nur empfehlen die ganze Seite zu lesen).


    1. Erstellen Sie eine 2d-Tensor (beispelsweise der Größe \(10 \times 10\)), der mit zufälligen ganzen Zahlen zwischen 1 und 10 gefüllt ist.
      Geben Sie jeweils einen Ausdruck an, der
      1. alle geraden Zahlen auf 0 setzt
      2. den Anteil gerader Zahlen in einer beliebigen Matrix zählt Tipp: .sum() direkt auf dem Bool-Tensor. Alle true-Werte werden als 1 gezählt, alle false-Werte als 0.
      3. alle Spalten quadriert, die mindestens eine 5 enthalten
      4. alle Diagonaleinträge auf 0 setzt.
      5. die erste Spalte und die erste Zeile vertauscht
    2. Erstellen Sie eine Funktion, die einen 2d-Tensor aus \(\{0,1\}^{n\times n}\) zurückgibt, der wie ein Schachbrett gefüllt ist.
      Hinweis: np.arange, np.reshape und % (Modulo) Operation reichen hier aus.
      Beispiel:
      > chess(9)
        tensor([[1, 0, 1, 0, 1, 0, 1, 0, 1],
                [0, 1, 0, 1, 0, 1, 0, 1, 0],
                [1, 0, 1, 0, 1, 0, 1, 0, 1],
                [0, 1, 0, 1, 0, 1, 0, 1, 0],
                [1, 0, 1, 0, 1, 0, 1, 0, 1],
                [0, 1, 0, 1, 0, 1, 0, 1, 0],
                [1, 0, 1, 0, 1, 0, 1, 0, 1],
                [0, 1, 0, 1, 0, 1, 0, 1, 0],
                [1, 0, 1, 0, 1, 0, 1, 0, 1]], dtype=torch.int32)
      
    3. Erstellen Sie eine Funktion, die einen „Hypercube“ der Kantenlänge 3 und Dimension n erstellt, bei dem jeweils überall eine 1 steht, außer im Zentrum, dort soll eine 0 stehen.
    4. Etwas schwerer: Erstellen Sie eine Funktion, die einen „Hypercube“ der Kantenlänge 3 und Dimension n erstellt, bei dem jeweils eine 1 auf jeder Ecke steht, ansonsten aber nur mit 0en gefüllt ist.
      Hinweis: Das Schwierige ist hier insbesondere keine Schleife zu verwenden. Konstruieren Sie zum Beispiel den Hypercube also für kleine Dimensionen per Hand, flatten (oder .reshape(-1)en) Sie den Würfel und prüfen Sie in welcher Frequenz sich die 1en befinden.
      Für die Lösung gibt es zwei möglichkeiten:
      1. Testen Sie, ob die Zahlenfolge der Indices unter Der Integer Sequence Database finden.
      2. Nutzen Sie np.meshgrid.
  4. Zuletzt etwas angewandteres: Pi bestimmen + visualisieren.
    Berechnen Sie näherungsweise \(\pi\) mit Hilfe von (Pseudo-)Zufallszahlen. Erzeugen Sie \(n\) zufällige Punkte innerhalb des Einheitsquadrates \([0,1]^2\) und testen Sie ob diese innerhalb des Einheitskreises (mit Radius 1) liegen. Aus der Anzahl der Punkte die innerhalb des Viertelkreises (wir haben ja nur positive Punkte gewürfelt) liegen und der der Gesamtanzahl \(n\) lässt sich \(\pi\) berechnen. Dazu nehmen wir an, dass das Verhältnis der Punkte innerhalb des Viertelkreises und aller Punkte genau das Verhältnis zwischen den Flächeninhalten des Viertelkreises und der Quadrats ist. \[ \frac{\text{Anzahl Punkte im Kreis}}{\text{Anzahl Punkte im Einheitsquadrat}} \approx \frac{A_\text{Viertelkreis mit Radius 1}}{A_\text{Einheitsquadrat}} = \frac{\pi}{4} \]

    1. Wählen Sie \(n:=1\) Million und geben Sie den berechneten Wert für \(\pi\) wie beschrieben aus.
    2. Visualisieren Sie das Experiment (etwa mithilfe eines Matplotlib Scatterplot).

Aufgabe 2: Numpy Katzen

Quelle: Die Katzen wurden freundlicherweise online von Robert W. Sumner bereitgestellt, im Rahmen der folgenden Publikation:
Robert W. Sumner, Jovan Popovic: Deformation Transfer for Triangle Meshes. In: ACM Transactions on Graphics. 23, 3 (Proc. ACM SIGGRAPH 2004), August 2004.

Die Daten für die Katzen befinden sich im oben verlinkten Archiv cat-poses.zip.
Die Dateien stellen jeweils ein Dreiecksnetz einer Katze in verschiedenen Posen dar. Dabei hat jede Katze genau die gleiche Anzahl an Eckpunkten, und die Eckpunkte sind Registriert (das heißt, sie sind immer konsistent durchnumeriert, so dass man zwischen Katzenposen einfach durch Interpolation der Eckpunkte überblenden kann). Mit anderen Worten: Der Vertex der linken Ohrspitze hat in allen Dateien den selben Index.

Pyrender mit Schiebregler und Tkinter
Die einfachste Möglichkeit dies zu realisieren ist wohl Tkinter, das Standard-GUI-Toolkit für Python, dass bei Mac und Windows direkt mit Python installiert wird.
Um eine interkative Animation zu erstellen, öffnen Sie zunächst den Pyrender Viewer in einem Thread wie in Blatt 0 beschrieben. Erstellen Sie dann den TK Viewer im Hauptthread.
from tkinter import *

# Ihr Code
# ...

# create pyrender viewer in thread
master = Tk()
w = Scale(master, from_=0, to=1, command=update, orient=HORIZONTAL,resolution=0.01)
w.set(0) # set default value
w.pack()
mainloop()

Sie können nun eine Funktion update(slider_value) definieren, die immer automatisch aufgerufen wird wenn der Slider bewegt wird und den Wert des Sliders automatisch als Argument übergeben bekommt.
In dieser Funktion sollten Sie den Pyrender Viewer wie im letzten Blatt beschrieben updaten können.


Aufgaben

  1. Katzenimport: Laden sie alle Katzen als Trimesh-Objekte ein und visualisieren Sie diese in 3d.
    Achten Sie beim Laden darauf, das Argument process=false zu übergeben, damit die Reihenfolge der Vertices nicht von Trimesh durcheinander gebracht wird.
    Nutzen Sie nur die Katzen im Hauptverzeichnis; die Meshes im Ordner „bad pose“ werden für diese Übung nicht gebraucht.
  2. Convex-Kombinationen von Katzen
    1. Berechnen Sie die mittlere Katze dadurch, dass Sie für jeden Eckpunkt den Mittelwert des Ortsvektors über alle Posen berechnen.

      Formal: Seien \(p_1^{(j)}, \dots, p_n^{(j)} \in \mathbb{R}^3\) die \(n\) Eckpunkte der Katze der Datei \(j\) (\(j \in {1,\dots,8}\)). Dann berechnen sich die Eckpunkte \(\mu_1, \dots, \mu_n \in \mathbb{R}^3\) der mittleren Katze durch: \[ \mu_i := \frac{1}{8} \sum_{j=1}^{8} p_i^{(j)}. \]
    2. Nachdem wir die mittlere Katze bestimmt haben, berechnen Sie nun dynamische Morphs zu allen anderen Katzen.

      Formal: Bestimmen wir die lineare Hülle (auch Span gennant) über der gegebenen Katzenbasis, d.h. die Menge aller Katzen, die sich durch Linearkombination aus den gegebenen Basisvektoren (also den 8 Differenz-Vektoren der verschiedenen Katzenposen zum Mittelpunkt) aufspannen lassen, \[ \left\{ \mu_i + \sum_{j=1}^{8} \lambda_j \cdot ( p_i^{(j)} - \mu_i ) \middle| \lambda_j \in \mathbb{R} \right\}. \]

      Hier entsprechen die achtdimensionalen Koordinaten \(\left(\lambda_1, \dots, \lambda_8\right) \in \mathbb{R}^8\) den Anteilen, die die einzelnen Katzenposen an der Gesamtposen haben, gemessen als Abstand vom Mittelwert.
      • Für gute Ergebnisse macht es Sinn, die Koordinaten so zu beschränken, dass eine Konvexkombination entsteht, also \(\sum_j \lambda_j = 1\) mit \(\lambda_j ≥ 0\) zu fordern.
      • Andere Werte (auch negative) liefern erheiternde Ergebnisse.
      • große Beträge für Lambda liefern skurrile Ergebnisse
      Implementieren Sie die Morphs als interaktive Animation mit einem Schiebregler für jedes \(\lambda_i\).
    3. Explorieren Sie den ganzen Katzen-Vektorraum (also nicht nur \(\lambda_i ≥ 0\) und \(\sum_i \lambda_i = 1\)) und präsentieren Sie ihre Lieblingskatze etwa als Bild im Teams Kanal zu diesem Übungsblatt. ;)