Schlagwort-Archive: analyse

OpenCV mit Processing – Basics_2


Processing 2.0

Merkmale isolieren – Konturen finden

Die Funktion threshold() dient der Isolierung der für die Mustererkennung relevanten Konturen. Sie blendet Pixel aus, deren Helligkeitswert einen bestimmten Schwellenwert unterschreitet, oder übersteigt.

Beispiel: Threshold

// Verändert von Thomas Koberger
// im Original von:
// Programme d'exemple de la librairie javacvPro
// par X. HINAULT - octobre 2011
// Tous droits réservés - Licence GPLv3

/**
* changing strokeweight and strokecaps on diagonals in a grid
*
* MOUSE
* left right Threshold 0-1
*
* KEYS

* n                   : show original Image

* 1                   : apply threshold "BINARY"
* 2                   : apply threshold "BINARY_INV"
* 3                   : apply threshold "TRUNK"
* 4                   : apply threshold "TOCERO"
* 5                   : apply threshold "TOCERO_INV"

* s                   : save png
*/

import monclubelec.javacvPro.*;
import java.util.*;

PImage img;

String url="http://kobe.bplaced.net/processing/016_16.JPG";
OpenCV opencv; // deklariert ein OpenCV Objekt

void setup() {

// Lädt die Bilddatei
img=loadImage(url, "jpg");

// initialisiert OpenCV ---
opencv = new OpenCV(this);
opencv.allocate(img.width, img.height); // initialisiert die Buffer von OpenCV

opencv.copy(img); // lädt die PImage Datei in den OpenCV Buffer

size (opencv.width(), opencv.height());

// gibt das Bild aus
image(opencv.getBuffer(), 0, 0);

noLoop();
}

void draw() {

noLoop();
}

void keyReleased() {

// Zum speichern des Bildes
if (key == 's' || key == 'S') saveFrame(timestamp()+"_##.png");

// Originalbild anzeigen
if (key == 'n') {
opencv.copy(img);
image(opencv.getBuffer(), 0, 0);
loop();
}

// Threshold Binary
if (key == '1') {
opencv.copy(img); // kopiert PImage in den OpenCV Buffer
opencv.threshold(map(mouseX,0,width,0,1), "BINARY"); // applique seuillage binaire avec seuil 0.5 sur le buffer princi
image(opencv.getBuffer(), 0, 0);// zeigt das Bild des Rot-Kanals
loop();
}

// Threshold Binary Invers
if (key == '2') {
opencv.copy(img); // kopiert PImage in den OpenCV Buffer
opencv.threshold(map(mouseX,0,width,0,1), "BINARY_INV");
image(opencv.getBuffer(), 0, 0);// zeigt das Bild des Grün-Kanals
loop();
}

// Threshold Trunk
if (key == '3') {
opencv.copy(img); // kopiert PImage in den OpenCV Buffer
opencv.threshold(map(mouseX,0,width,0,1), "TRUNK");
image(opencv.getBuffer(), 0, 0);// zeigt das Bild des Blau-Kanals
loop();
}

// Threshold Tozero
if (key == '4') {
opencv.threshold(map(mouseX,0,width,0,1), "TOZERO");
image(opencv.getBuffer(), 0, 0);
loop();
}

// Threshold Tozero Invers
if (key == '5') {
opencv.copy(img);
opencv.threshold(map(mouseX,0,width,0,1), "TOZERO_INV");
image(opencv.getBuffer(), 0, 0);
loop();
}
}

// timestamp
String timestamp() {
Calendar now = Calendar.getInstance();
return String.format("%1$ty%1$tm%1$td_%1$tH%1$tM%1$tS", now);
}

Beispiel: Konturen finden

Um Merkmale analysieren zu können, ist es vorher notwendig die markanten Unterschiede zu finden. Geht es um Form, ist es wichtig die Konturen von Objekten zu finden. Für diese Aufgaben kommen die vier hier im Beispiel vorgestellten Filter in Frage.

  1. canny(), canny(Grenzwert1, Grenzwert2), canny(Grenzwert1, Grenzwert2, Faltungskern)
    Die Werte für den Grenzwert1 sind meist zwischen 100 und 200 optimal, Grenzwert2 = 2*Grenzwert1.
    Der Standard für den Faltungskern ist 3, das bedeutet es werden 3*3 Pixel analysiert.
  2. scobel(), scobel(Faltungskern, Maßstab)
    Faltungskern – siehe oben, Maßstab wird mit dem Faltungskern multipliziert.
  3. scharr(),  scharr(Maßstab)
  4. scobel2(), scobel2(Koeffizient), scobel2(Faltungskern, Maßstab, Koeffizient)


// Verändert von Thomas Koberger
// im Original von:
// Programme d'exemple de la librairie javacvPro
// par X. HINAULT - octobre 2011
// Tous droits réservés - Licence GPLv3

/**
* changing strokeweight and strokecaps on diagonals in a grid
*
* MOUSE
*
*
* KEYS
* 1                   : show canny()
* 2                   : show Scobel()
* 3                   : show ScHARR
* 4                   : show scobel2
* n                   : show original Image

* s                   : save png
*/

import monclubelec.javacvPro.*;
import java.util.*;

PImage img;

String url="http://kobe.bplaced.net/processing/016_16.JPG";
OpenCV opencv; // deklariert ein OpenCV Objekt

void setup() {

// Lädt die Bilddatei
img=loadImage(url, "jpg");

// initialisiert OpenCV ---
opencv = new OpenCV(this);
opencv.allocate(img.width, img.height); // initialisiert die Buffer von OpenCV

opencv.copy(img); // lädt die PImage Datei in den OpenCV Buffer

size (opencv.width(), opencv.height());

// gibt das Bild aus
image(opencv.getBuffer(), 0, 0);
noLoop();
}

void draw() {

noLoop();
}

void keyReleased() {
if (key == 's' || key == 'S') saveFrame(timestamp()+"_##.png");

if (key == '1') {
opencv.copy(img); // kopiert PImage in den OpenCV Buffer
opencv.canny(100,200,3); // Filter canny()
image(opencv.getBuffer(), 0, 0);// zeigt das Bild des Rot-Kanals
loop();
}

if (key == '2') {
opencv.copy(img); // kopiert PImage in den OpenCV Buffer
opencv.sobel(3,0.9); // Filter Scobel
image(opencv.getBuffer(), 0, 0);// zeigt das Bild des Grün-Kanals
loop();
}

if (key == '3') {
opencv.copy(img); // kopiert PImage in den OpenCV Buffer
opencv.scharr(0.4); // Filter ScHARR
image(opencv.getBuffer(), 0, 0);// zeigt das Bild des Blau-Kanals
loop();
}

if (key == '4') {
opencv.copy(img);
opencv.sobel2(3,4,1);
image(opencv.getBuffer(), 0, 0);
loop();
}

if (key == 'n') {
opencv.copy(img);
image(opencv.getBuffer(), 0, 0);
loop();
}
}

// timestamp
String timestamp() {
Calendar now = Calendar.getInstance();
return String.format("%1$ty%1$tm%1$td_%1$tH%1$tM%1$tS", now);
}

Veränderungen zwischen Frames erkennen

… kann man mit der Funktion:

  • sum()         …gibt die Summe der Helligkeitswerte aller Pixel zurück
  • sumRGB() …gibt ein Array mit der Summe der Helligkeitswerte der einzelnen Farbkanäle zurück
  • sumR()     ……gibt die Summe der Helligkeitswerte des R-Kanals zurück
  • sumG()     ……gibt die Summe der Helligkeitswerte des G-Kanals zurück
  • sumB()     ……gibt die Summe der Helligkeitswerte des B-Kanals zurück

Dies ist praktisch, da sich in Videos daraus leicht die ablesen lässt, wie stark sich einzele Frames voneineander unterscheiden.

Obiges Beispiel kann mit folgender Zeile ergänzt werden, um die sum()-Werte auszulesen:

(in draw(), case: ’n‘)

println(opencv.sum());

Mit sum() kann man das Maß der Veränderung zwischen zwei Frames in Zahlen auslesen. Oft braucht man diese Veränderungen auch als Bild. Dafür stellt OpenCV die Funtktion absDiff() zur Verfügung. Sie liest den aktuellen Buffer ein, vergleicht ihn mit dem Inhalt von Memory und speichert die Differenz als Bild-Buffer in Memory2 ab. Zusammen mit threshold(BINARY) kann man damit einen einfärbigen Hintergrund gut von einem Objekt isolieren.

Beispiel: Veränderung vom Frames zeichnen mit absDiff()


// Verändert von Thomas Koberger
// im Original von:
// Programme d'exemple de la librairie javacvPro
// par X. HINAULT - octobre 2011
// Tous droits réservés - Licence GPLv3

/**
* KEYS
* Space                   : remember Frame
* s                       : save png
*/
import processing.video.*;
import monclubelec.javacvPro.*;
import java.util.*;

// Für WebCam:
Capture cam1;
//GSMovie cam1;

OpenCV opencv; // deklariert ein OpenCV Objekt

void setup() {

// Für WebCam:
cam1= new Capture(this, 640, 360);
//cam1 = new GSMovie(this, "em.mpg");

// für WebCam:
cam1.start();
//cam1.play();

// initialisiert OpenCV ---
opencv = new OpenCV(this);

//Vorsicht: bei der Arbeit mit einer Datei muss die Größe genau passen!!!
opencv.allocate(640, 360);

// Für WebCam:
// opencv.allocate(cam1.width, cam1.height); // initialisiert die Buffer von OpenCV
size (opencv.width(), opencv.height());
frameRate(60);
}

void draw() {

// Dateien und die WebCam brauchen etwas Zeit zum Laden
if (cam1.available()) {

// Einzelne Frames werden gelesen
cam1.read();
opencv.copy(cam1);
image(opencv.getBuffer(), 0, 0);
opencv.absDiff();
image(opencv.getMemory2(), 0, 0);
}
}

void keyReleased() {
if (key == 's' || key == 'S') saveFrame(timestamp()+"_##.png");
}
void keyPressed() {
if (key==' ') {
opencv.remember();  // Schreibt den aktuellen Buffer in Memory
}
}

// timestamp
String timestamp() {
Calendar now = Calendar.getInstance();
return String.format("%1$ty%1$tm%1$td_%1$tH%1$tM%1$tS", now);
}

Eine noch einfachere und nicht minder effiziente Art der Hintergrund- Subtraktion bieten der bgsMOG und bgsMOG2 Algotithmus.

Beispiel: Veränderung vom Frames zeichnen mit bgsMOG und bgsMOG2



// Verändert von Thomas Koberger
// im Original von:
// Programme d'exemple de la librairie javacvPro
// par X. HINAULT - octobre 2011
// Tous droits réservés - Licence GPLv3

/**
* KEYS
* Space                   : remember Frame
* s                       : save png
*/
import processing.video.*;
import monclubelec.javacvPro.*;
import java.util.*;

// Für WebCam:
Capture cam1;
//Movie cam1;

OpenCV opencv; // deklariert ein OpenCV Objekt

void setup() {

// Für WebCam:
cam1= new Capture(this, 640, 360);
//cam1 = new Movie(this, "em.mpg");

// für WebCam:
cam1.start();
//cam1.play();

// initialisiert OpenCV ---
opencv = new OpenCV(this);

//Vorsicht: bei der Arbeit mit einer Datei muss die Größe genau passen!!!
opencv.allocate(640, 360);
opencv.bgsMOGInit(20, 5, 0.5, 10);
//opencv.bgsMOG2Init(1000, 16, false);

// Für WebCam:
//opencv.allocate(cam1.width, cam1.height); // initialisiert die Buffer von OpenCV
size (opencv.width(), opencv.height());
frameRate(60);
}

void draw() {

// Dateien und die WebCam brauchen etwas Zeit zum Laden
if (cam1.available()) {

// Einzelne Frames werden gelesen
cam1.read();
opencv.copy(cam1);
image(opencv.getBuffer(), 0, 0);
opencv.bgsMOGApply(opencv.Buffer, opencv.BufferGray, 0);
//opencv.bgsMOG2Apply(opencv.Buffer, opencv.BufferGray, -1);
image(opencv.getBufferGray(), 0, 0);
}
}

void keyReleased() {
if (key == 's' || key == 'S') saveFrame(timestamp()+"_##.png");
}

// timestamp
String timestamp() {
Calendar now = Calendar.getInstance();
return String.format("%1$ty%1$tm%1$td_%1$tH%1$tM%1$tS", now);
}

Minim – Audio Analyse


Pegel Spektrum zeichnen

Um ein Pegel Spektrum darzustellen, kann man aus der AudioSource den AudioBuffer mix auslesen. Die Methode toArray() des AudioBuffers mix gibt ein Float Array mit den einzelnen Pegeln im Buffer zurück. Diese Werte kann man dann verwenden, um ein Spektrum zu zeichnen. Ich habe für die Darstellung dann der Einfachheit halber Rechtecke gewählt.

Achtung: Es handelt sich hier um ein Spektrum der Pegel über die Zeit, nicht um ein Frequenzspektrum!

Beispiel: Spektrum zeichnen


// Library importieren
import ddf.minim.*;

// Objekte erstellen
Minim minim;
AudioPlayer input;

int x, y;

// Anzahl der Peaks
int grid=128;

// Abstand zwischen den Peaks
int spacing=1;

// Ausschlagmaximum für Peaks festlegen
float yScale = 2;

void setup() {
size(1024, 400);
smooth();
noStroke();

// Konstruktor des Minim Objekts aufrufen
minim = new Minim(this);

// Livestream vom FM4 laden, Größe des default sample buffer's ist 1024
input = minim.loadFile("http://mp3stream1.apasf.apa.at:8000");

// Wiedergabe starten
input.play();
}

void draw() {

// für etwas Bewegunsunschärfe
fill(50, 10);
rect(0, 0, width, height);

// Auslesen und speichern des Spektrums
float[] buffer = input.mix.toArray();

// Breite der Rechtecke berechnen
for (int i=1; i <= buffer.length; i+=buffer.length/grid) {
float x = map(i, 0, buffer.length, 0, width);
float y = map(buffer[i-1]*yScale, -1, 1, 0, height) ;
fill (102, 145, 250,100);

// Rechteck zeichnen
rect(x+spacing, height, width/grid-2*spacing, -y);
}
}

void stop()
{
// Player in schließen
input.close();
// Minim Object stoppen
minim.stop();

super.stop();
}

Frequenzen darstellen

Der Begriff Spekturm bezieht sich in der Regel auf ein Frequenzspektrum. Dieses kann mit Hilfe der Klasse FFT  und der forward() Methode aus dem AudioBuffer errechnet werden. Dafür werden die Pegel im Buffer einer Fourier-Transformation unterzogen. Als Ergebnis erhält man keine einzelnen Frequenzen, sondern Frequenzbänder.

Umgekehrt kann man auch aus einem Frequenzspektrum ein Zeit-Pegel Spektrum ausgeben. Die Methode dafür heißt inverse();

Der auswertbare Frequenzbereich kann außerdem die halbe Sample-Frequenz nicht übersteigen. Die default Sample-Frequenz bei .mp3 und auf CD ist 44100 Hz, was eine maximale Frequenz von 22050 Hz für die Auwertung ergibt.

Einfaches Frequenzspektrum zeichnen

Um die FFT Klasse nutzen zu können, müssen wir zusätzlich zum letzten Beispiel die minim.analysis – Bibliothek importieren.

import ddf.minim.analysis.*;

Der folgende Code stellt ein Abwandlung des obigen Beispiels dar. Er zeichnet die Frequenzspektren der beiden Kanäle (left und right).

Beispiel: FFT Frequenzspektrum linear

// Library importieren
import ddf.minim.*;
import ddf.minim.analysis.*;

// Objekte erstellen
Minim minim;
AudioPlayer input;
FFT fftR, fftL;

int x, y;

// Anzahl der Peaks
int grid=32;

// Abstand zwischen den Peaks
int spacing=1;

// Ausschlagmaximum für Peaks festlegen
float yScale = 1;

void setup() {
size(1024, 400);
smooth();
noStroke();

// Konstruktor des Minim Objekts aufrufen
minim = new Minim(this);

// Livestream vom FM4 laden, Größe des default sample buffer's ist 1024
input = minim.loadFile("http://mp3stream1.apasf.apa.at:8000");

// Wiedergabe starten
input.play();
input.printControls();

// FFT-Instanz für die Spektrumsanalyse der beiden Kanäle
fftR = new FFT (input.bufferSize (), input.sampleRate ());
fftL = new FFT (input.bufferSize (), input.sampleRate ());
}

void draw() {

// für etwas Bewegunsunschärfe
fill(50, 10);
rect(0, 0, width, height);

// forwar FFT Analyse durchführen
fftR.forward(input.right);
fftL.forward(input.left);

// rechter Kanal
fill(255);
text("right Channel", 10, height/2+20);

// Breite der Rechtecke berechnen
for (int i=1; i <= fftR.specSize(); i+=fftR.specSize()/grid) {
float x = map(i, 0, fftR.specSize(), 0, width);
float y = map(fftR.getBand(i)*yScale, 0, 100, 0, height/2) ;
fill (102, 145, 250, 100);

// Rechteck zeichnen
rect(x+spacing, height, width/grid-2*spacing, -y);
}

// linker Kanal
fill(255);
translate(0, -height/2);
text("left Channel", 10, height/2+20);

// Breite der Rechtecke berechnen
for (int i=1; i <= fftL.specSize(); i+=fftL.specSize()/grid) {
float x = map(i, 0, fftL.specSize(), 0, width);
float y = map(fftL.getBand(i)*yScale, 0, 100, 0, height/2) ;
fill (102, 145, 250, 100);

// Rechteck zeichnen
rect(x+spacing, height, width/grid-2*spacing, -y);
}
}

void stop()
{
// Player in schließen
input.close();
// Minim Object stoppen
minim.stop();

super.stop();
}

Wie man an dem Spektrum unschwer erkennen kann, entspricht die Darstellung nicht unserer Wahrnehmung. Eine logarithmische Darstellung der Frequenzen ist hier angebracht. Mit FFT Klasse kann man eine solche Umwandlung mit der Methode logAverages() vornehmen.

Beispiel: FFT Frequenzspektrum logarithmisch



// Library importieren
import ddf.minim.*;
import ddf.minim.analysis.*;

// Objekte erstellen
Minim minim;
AudioPlayer input;
FFT fftR, fftL;

int x, y;

// Anzahl der Peaks
int grid=20;

// Abstand zwischen den Peaks
int spacing=5;

// Ausschlagmaximum für Peaks festlegen
float yScale = 1;

void setup() {
  size(1024, 400);
  smooth();
  noStroke();

  // Konstruktor des Minim Objekts aufrufen
  minim = new Minim(this);

  // Livestream vom FM4 laden, Größe des default sample buffer's ist 1024
  input = minim.loadFile("http://mp3stream1.apasf.apa.at:8000";,2048);

  // Wiedergabe starten
  input.play();
  input.printControls();

  // FFT-Instanz für die Spektrumsanalyse der beiden Kanäle
  fftR = new FFT (input.bufferSize (), input.sampleRate ());
  fftL = new FFT (input.bufferSize (), input.sampleRate ());
  fftR.logAverages(11, 16);
  fftL.logAverages(11, 16);
}

void draw() {

  // für etwas Bewegunsunschärfe
  fill(50, 10);
  rect(0, 0, width, height);

  // forwar FFT Analyse durchführen
  fftR.forward(input.right);
  fftL.forward(input.left);

  // rechter Kanal
  fill(255);
  text("right Channel", 10, height/2+20);

  // Breite der Rechtecke berechnen
  for (int i=0; i < fftR.avgSize(); i+=fftR.avgSize()/grid) {
    //println(fftR.avgSize());
    float x = map(i, 0, fftR.avgSize(), 0, width);
    //println(fftR.getAvg(i));
    float y = map(fftR.getAvg(i)*yScale, 0, 100, 0, height/5) ;
    fill (102, 145, 250, 100);

    // Rechteck zeichnen
    rect(x+spacing, height, width/grid-2*spacing, -y);
  }

  // linker Kanal
  fill(255);
  translate(0, -height/2);
  text("left Channel", 10, height/2+20);

  // Breite der Rechtecke berechnen
  for (int i=0; i < fftL.avgSize(); i+=fftL.avgSize()/grid) {
    float x = map(i, 0, fftL.avgSize(), 0, width);
    float y = map(fftL.getAvg(i)*yScale, 0, 100, 0, height/5) ;
    fill (102, 145, 250, 100);

    // Rechteck zeichnen
    rect(x+spacing, height, width/grid-2*spacing, -y);
  }
}

void stop()
{
  // Player in schließen
  input.close();
  // Minim Object stoppen
  minim.stop();

  super.stop();
}

Eine weitere Möglichkeit der FFT Klasse ist die Veränderung der Pegel einzelner Frequenzbereiche mit scaleBand() und setBand(). Siehe dazu die JavaDoc.

Beat Detection

Auch hier gibt es wieder 2 Möglichkeiten. Einerseits kann man nur mit den Levels (Amplituden) arbeiten - SOUND_ENERGY. Oder aber man nutzt FREQUENCY_ENERGY und greift die Levels in einzelnen Frequenzbändern ab.

Beispiel: BeatDetect mit SoundEnergy

// Library importieren
import ddf.minim.*;
import ddf.minim.analysis.*;

// Objekte erstellen
Minim minim;
AudioPlayer input;
BeatDetect beat;

float eRadius;

void setup() {
size(512, 512);
smooth();
noStroke();

// Konstruktor des Minim Objekts aufrufen
minim = new Minim(this);

// Livestream vom FM4 laden, Größe des default sample buffer's ist 1024
input = minim.loadFile("http://mp3stream1.apasf.apa.at:8000");

// Wiedergabe starten
input.play();
input.printControls();

// Erstellt die BeatDetect Instanz
beat = new BeatDetect();

ellipseMode(CENTER_RADIUS);
}

void draw() {

// für etwas Bewegunsunschärfe
fill(50, 50);
rect(0, 0, width, height);

// Initiiert die BeatDetection
beat.detect(input.mix);

fill (102, 145, 250, 100);

// Trigger der BeatDetection
if ( beat.isOnset() ) eRadius = 3;

if ( eRadius < 0.1 ) eRadius = 0.1;

// Zeichnet die Kreise
for (float i=1;i<10;i+=0.3) {
fill(102, 145, 250, 10/i*i);
ellipse(width/2, height/2, eRadius*i*i, eRadius*i*i);
}
eRadius *= 0.95;
}

void stop()
{
// Player in schließen
input.close();
// Minim Object stoppen
minim.stop();

super.stop();
}

Beispiel: BeatDetect mit FrequencyEnergy

Hier kann man mit den Methoden isKick(), isSnare() und isHat() Peaks in den Frequenzbändern abrufen, die den jeweiligen Schlagzeugbausteinen entsprechen. Das funktioniert allerdings nicht bei allen Musiktypen gleich gut. Bei Problemen kann man noch auf die Funktion isRange(int low, int high, int threshold) zurückgreifen.

// Library importieren
import ddf.minim.*;
import ddf.minim.analysis.*;

// Objekte erstellen
Minim minim;
AudioPlayer input;
BeatDetect beat;
BeatListener bl;

float radKick, radSnare, radHat;

void setup() {
size(1024, 512);
smooth();
noStroke();

// Konstruktor des Minim Objekts aufrufen
minim = new Minim(this);

// Livestream vom FM4 laden, Größe des default sample buffer's ist 1024
input = minim.loadFile("http://mp3stream1.apasf.apa.at:8000");

// Wiedergabe starten
input.play();
input.printControls();

// Erstellt die BeatDetect Instanz
// Im Frequency Mode müssen BufferSize und SampleRate übergeben werden.
beat = new BeatDetect(input.bufferSize(), input.sampleRate());

//Setzt die Zeit, in der der Algorithmus keine weiteren Beats meldet
beat.setSensitivity(200);
ellipseMode(CENTER_RADIUS);
textAlign(CENTER, CENTER);
}

void draw() {

// für etwas Bewegunsunschärfe
fill(50, 100);
rect(0, 0, width, height);

// Initiiert die BeatDetection
beat.detect(input.mix);

fill (102, 145, 250, 100);

// Trigger der BeatDetection
if ( beat.isKick() ) radKick = 2.5;
if ( beat.isSnare() ) radSnare = 2.5;
if ( beat.isHat() ) radHat = 2.5;

if ( radKick < 0.1 ) radKick = 0.1;
if ( radSnare < 0.1 ) radSnare = 0.1;
if ( radHat < 0.1 ) radHat = 0.1;

// Zeichnet die Kreise
for (float i=1;i<10;i+=0.3) {
fill(102, 145, 250, 10/i*i);
ellipse(width/4, height/2, radKick*i*i, radKick*i*i);
}

// Zeichnet die Kreise
for (float i=1;i<10;i+=0.3) {
fill(255, 0, 50, 10/i*i);
ellipse(width/2, height/2, radSnare*i*i, radSnare*i*i);
}

// Zeichnet die Kreise
for (float i=1;i<10;i+=0.3) {
fill(255, 200, 0, 10/i*i);
ellipse(width*3/4, height/2, radHat*i*i, radHat*i*i);
}

//Zeichnet den Text
fill(255);
text("Kick", width/4, height/2);
text("Snare", width/2, height/2);
text("Hat", width*3/4, height/2);

radKick *= 0.9;
radSnare *= 0.9;
radHat *= 0.9;
}

void stop()
{
// Player in schließen
input.close();
// Minim Object stoppen
minim.stop();

super.stop();
}