Quiz/KlausurSS23

Revision as of 09:11, 9 October 2023 by Leonie (talk | contribs) (→‎Learning Graph: update template)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

The SS23 exam with solutions. Try to solve it by yourself before checking the solution. missing LINK!

NOTE: All questions and answers are provided in german, as they appeared in the exam.

Grundwissen (12P.)

Aussagen

Bitte geben Sie für jede der folgenden Aussagen an, ob sie wahr oder falsch ist, indem Sie "W" oder "F" davorschreiben. Für falsche Antworten gibt es Punktabzug.

  1. Der Bresenham-Algorithmus dient dazu, Kanten in Bildern zu finden.
  2. Der OpenGL Immediate Mode ist effizienter als Shader-basierte Alternativen.
  3. OpenCV bietet Funktionen, um ein GUI zu implementieren.
  4. Der Painter's Algorithm zeichnet jeden Pixel genau einmal.
  5. Bezier-Kurven können mit dem De-Hondt-Verfahren berechnet werden.
  6. Wenn man einen Weichzeichnungs-Filter auf ein Bild anwendet, bleibt die durchschnittliche Helligkeit aller Pixel im Bild gleich.
Lösung
Die Richtigen Antworten lauten:
  1. Falsch. Der Bresenham-Algorithmus dient dazu, Linien zu zeichnen
  2. TODO
  3. TODO
  4. TODO
  5. TODO
  6. TODO


Außenseiter

In jeder Zeile gehört ein Begriff nicht zu den anderen. Markiern Sie diesen fett.

  1. GLSL - GLEW - GLUT - GIMP
  2. Translucent - Ambient - Specular - Diffuse
  3. NeRF - SDF - Mesh - Graph
  4. Faltung - Rotation - Translation - Skalierung
  5. Vertex - Voxel - Vektor - Voltage
  6. ORB - ATOL - SURF - SIFT
Lösung
1: GIMP



Bildbearbeitung (30 P.)

Laden Sie das Bild "images/objects.jpg" (5 P.) und verbessern Sie es mittels OpenCV-Funktionen wie folgt:

  • der Kontrast soll maximiert werden (d.h. der hellste Pixel im Bild soll weiß werden, der dunkelste Pixel im Bild soll schwarz werden) (5 P.)
  • das Bild soll stark weichgezeichnet werden (5 P.)
  • über das Bild soll - halbtransparent und bildfüllend - der Schriftzug "CGBV" als Wasserzeichen gelegt werden (15 P.)

Verwenden Sie nur Numpy-/OpenCV-Funktionen.

Zeigen Sie das Bild im Notebook an (es muss nicht gespeichert werden)

img = None
# Hier könnte Ihre Lösung stehen!
show(img)



Lösung
# add Musterlösung


2D/3D-Grafik (39 P.)

Untenstehender Code soll einen sich drehenden, pulsierenden 3D-Würfel zeigen, dessen Farbe sich kontinuierlich ändert. Leider sind einige Bugs im Code. Beheben Sie diese:

  • drei Syntaxfehler (9 P.)
  • irgendwie ist der Würfel defekt. Korrigieren Sie seine Definition (5 P.)
  • die orthogonale Projektion sieht nicht schön aus. Verwenden Sie die perspektivische Projektion (5 P.)


Außerdem fehlt noch etwas Code. Ergänzen Sie diesen:

  • kontinuierliche Farbänderung - volle Punktzahl für loopenden Farbwechsel (15 P.)
    • Tipp 1: HSV macht das einfacher.
    • Tipp 2: wenn Sie fremden Code verwenden, achten Sie darauf, welchen Wertebereich die zurückgegebenen Werte haben.
    • Tipp 3: Sie können die Werte in einem Numpy-Array einfach skalieren, indem Sie dieses mit einer Zahl multiplizieren.
  • Lassen Sie den Würfel pulsieren, indem Sie seine Größe ändern (5 P.)
Code
# Define our simple 3D cube

#    1 - - - - - 7
#    - \         - \
#    -   3 - - - - - 5
#    -   -       -   -
#    -   -       -   -
#    -   -       -   -
#    0 - - - - - 6   -
#      \ -         \ -
#        2 - - - - - 4

cube_corners=[[-0.5, -0.5, -0.5],  # 0
              [-0.5, -0.5, 0.5],    # 1
              [-0.5, 0.5, -0.5],   # 2
              [-0.5, 0.5, 0.5],     # 3
              [0.5, 0.5, -0.5],    # 4
              [0.5, 0.5, 0.5],      # 5
              [0.5, -0.5, -0.5],   # 6
              [0.5, -0.5, 0.5]]     # 7

cube_edges = [(0, 2), (2, 4), (4, 6), (6, 0),
              (1, 3), (3, 5), (5, 7), (6, 1)
              (0, 1), (2, 3), (4, 5), (6, 2)]


def transform(points, angle=45):
    T = M([[1, 0, 0, 0],
           [0, 1, 0, 0],
           [0, 0, 1, 5],
           [0, 0, 0, 1]])
    
    cosa = cos(pi*angle/180)
    sina = sin(pi*angle/180)
    R = M([[cosa, 0, sina, 0],
           [0, 1, 0, 0],
           [-sina, 0, cosa, 0],
           [0, 0, 0, 1]])
 
    transformed_points = []
    for p in points:
        p_hom = p + [1]
        p_new = T @ R @ p_hom
        transformed_points.append(p_new)
    return transformed_points
        
def project(points, width=200, height=200, camera_distance = 2):
    P = M([[1, 0, 0, 0],
           [0, 1, 0, 0],
           [0, 0, 0, 0],
           [0, 0, 0, 1]])
    projected_points = []
    for p in points:
        p_new = P @ np.transpose(p)
        # assume points between -0.5 and 0.5
        x = int((float(p_new[0]/p_new[3]) + 0.5) * width)
        y = int((float(p_new[1]/p_new[3]) + 0.5) * width)
        projected_points.append((x,y))
    return projected_points

def cube(rotation=0, color=(255,255,255))
    projected_points = project(transform(cube_corners, rotation))
    cube_preview = np.zeros((200,200,3), np.unit8)
    for edge in cube_edges:
        p1 = projected_points[edge[0]]
        p2 = projected_points[edge[1]]
        cv2.line(cube_preview, p1, p2, color, 2)
    cube_preview = cv2.cvtColor(cube_preview, cv2.COLOR_BGR2RGB) # Converting BGR to RGB
    return(Image.fromarray(cube_preview))


from IPython.display import DisplayHandle
from time import sleep
d = DisplayHandle()
d.display(cube())


angle = 0
color = (255,255,0)
while True:
    angle += 5
    if angle > 360:
        angle = 0
    d.update(cube(angle, color))
    sleep(0.016)


Achtung: Hier muss man ggf. auf den "Interrupt Kernel"-Button klicken bzw. zweimal die Taste "I" drücken, um den Loop abzubrechen

Lösung
# add Musterlösung



Bildverarbeitung (35 P.)

Laden Sie das Bild "objects2.jpg". Schreiben Sie Code, der folgendes macht:

  • Zeichnen Sie die Positionen aller ARUco-Marker ein. (10 P.)
  • Ermitteln Sie, welche Farbe im Bild am häufigsten vorkommt und geben Sie diese aus. (5 P.)
  • Übermalen Sie alle ARUco-Marker mit dieser Farbe (5 P.)
  • Markieren Sie alle blauen/violetten Legosteine, die im Bild sind. (15 P.)

(Tipp: HSV, Threshold um blaue Steine zu extrahieren, findContours() + contourArea() um Objekte der passenden Größe zu finden).

orig = cv2.imread("images/objects2.jpg")
# magic needs to happen here!
show(orig)



GLSL (20 P.)

Zeichnen Sie eine simple 2D-Szene mit einem Fragment Shader und ggf. SDFs. Die Szene soll mindestens folgende Objekte oder ähnlich komplexe Elemente beinhalten:

  • einen blauen Himmel / Hintergrund (5 P.)
  • eine gelbbraune flache Wüste im Vordergrund (5 P.)
  • eine kreisförmige Sonne am Himmel. (10 P.)

Schreiben Sie einen passenden Shader in GLSL. Sie können dazu untenstehenden Code erweitern oder einen Shader in ShaderToy schreiben und in die folgende Zelle einfügen.

Code
# Hier ggf. ShaderToy-Code einfügen


vertex_code = """
    attribute vec2 position;
    void main(){ gl_Position = vec4(position, 0.0, 1.0); } """

fragment_code = """

    void main() {
        gl_FragColor = vec4(0.4, 1.0, 1.0, 1.0); 
    } """

# -----------------------------------------------------------------------------
# Python & OpenGL for Scientific Visualization
# www.labri.fr/perso/nrougier/python+opengl
# Copyright (c) 2017, Nicolas P. Rougier
# Distributed under the 2-Clause BSD License.
# -----------------------------------------------------------------------------
import sys
import ctypes
import numpy as np
import OpenGL.GL as gl
import OpenGL.GLUT as glut

def display():
    gl.glClear(gl.GL_COLOR_BUFFER_BIT)
    gl.glDrawArrays(gl.GL_TRIANGLE_STRIP, 0, 4)
    glut.glutSwapBuffers()

def reshape(width,height):
    gl.glViewport(0, 0, width, height)

def keyboard( key, x, y ):
    if key == b'\x1b':
        sys.exit( )

# GLUT init
# --------------------------------------
glut.glutInit()
glut.glutInitDisplayMode(glut.GLUT_DOUBLE


Lösung
# add Musterlösung



Learning Graph

A Graph that shows all items mentioned in the exam and their direct dependencies.

The learning path to Q390