Schlagwort-Archiv: tracking

vom Bild zum Sound- Wie aus Pixeln Töne werden (1/2)

Wie der aufmerksame Leser vielleicht weiß, können mit Midiola, auch physisch reale Notenrollen via Webcam/Handycam in Töne verwandeln. Das Grundprinzip ist das gleiche wie beim Abspielen der gescannten Rollen. Es werden 30xSekunde sehr schmale Bildausschnitte mit der Computer Vision Bibliothek trackingjs analysiert. Diese Bildauschnitte sind bei uns  wenige Pixel breit und werden entweder aus dem aktuellen Scrollbereich des Scans oder eben dem aktuellen Frame der Kamera extrahiert. Im ersten Teil soll es zunächst darum gehen wie aus den Farbwerten der Pixel letztlich Töne werden. Im zweiten Teil widme ich mich den Probleme die es dabei mit der Webcam und zitternden Händen gibt.

 

Jetzt haben wir also einen z.B. 15×2000 Pixel großen Bildausschnitt (siehe Bild 1), wie macht man daraus nun  Töne?

scanbereich_roh
Bild 1

 

Um sich dieser Herausforderung zu nähern müssen wir die Notation von der Papierfarbe und anderen unwichtigen Bildinformationen trennen. Optimalerweise bekommen wir am Ende eine Bounding Box die sich mit der Fläche der Note deckt.
Bei den gescannten Rollen sind diese Fläche meist Rot oder Grün.

scanbereich
Bild 2

Praktischerweise kann das erwähnte trackingjs genau das, also farbige Flächen als Rechtecke zurückliefern. Fürs Debugging, aber auch für den Benutzer ist es praktisch diese zurückgelieferten Rechtecke über das Bild der Rolle zu legen (Bild 2). So kann intuitiv man sehen ob eine Note richtig erkannt als solche erkannt wurde um ggf. an der Erkennung zu schrauben oder sich einfach zu freuen wenn Sound und Note synchron sind.

An diesem Schritt angelangt, besitzt Midiola eine Liste aller vermeintlich erkannten Notenfläche (bzw. deren Bounding Boxen). Das sieht dann so aus:
[{"width":264,"height":8,"x":0,"y":0,"color":"scannedNotationColor"},{"width":12,"height":8,"x":648,"y":0,"color":"scannedNotationColor"},{"width":12,"height":8,"x":801,"y":0,"color":"scannedNotationColor"},{"width":13,"height":8,"x":974,"y":0,"color":"scannedNotationColor"},{"width":11,"height":8,"x":1170,"y":0,"color":"scannedNotationColor"},{"width":12,"height":8,"x":1321,"y":0,"color":"scannedNotationColor"},{"width":12,"height":8,"x":1428,"y":0,"color":"scannedNotationColor"},{"width":276,"height":8,"x":1730,"y":0,"color":"scannedNotationColor"}]

Bild 3: Scanbereich mit erkannten Noten und beschrifteten X-Koordinaten
Bild 3: Scanbereich mit erkannten Noten und beschrifteten X-Koordinaten

An der width kann man erkennen, dass alle Noten im Mittel 12 Pixel Breit sind. Auffällig sind der erste und der letzte Eintrag. Deren Breite ist ~20-mal größer als der Rest. Hierbei handelt es sich um die beiden äußeren Ränder, die die gleiche Farbe wie die Noten besiten. Für die Tonerzeugung ist vor allem die X-Koordinate interessant. Diese kann durch Mapping auf eine andere Skala in für die Tonerzeugung relevante Werte transformiert werden. Je größer der X-Wert desto höher soll etwa der Ton sein usw.

Ein naives Mapping für MIDI-Töne (im Bereich von 21-108) sähe etwa so aus:

sei
function map(x, in_min, in_max, out_min, out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

dann:
map(rect.x, 0, 2000, 21, 108)

mit
rect = {"width":11,"height":8,"x":1170,"y":0,"color":"scannedNotationColor"}

gleich MIDI-Note 72.

Da wir die Ränder recht unrpoblematisch identifizieren können, wie oben gesehen, können wir unser Mapping weiter optimieren. Statt die horizontale Ausdehnung des gesamten Bildes/Scanstreifens in die Mappingfunktion einzusetzen (0, 2000), ist es sinnvoller nur den Bereich zwischen den Rändern zu betrachten (264, 1730):
map(rect.x, 264, 1730, 21, 108)

Dieses Vorgehen führt zu einer robusteren Berechnung unserer Notenwerte, da Unregelmäßigkeiten beim Scan weniger ins Gewicht fallen.

Im zweiten Teil geht es im die Probleme die sich im Livemodus ergeben.