Indisciplinarité

Catégorie : germe de code

Notes sur l’ « Esthétique des systèmes » de Jack Burnam.

Objets, forme, relation

Dans Esthétiques des systèmes, Jack Burnam esquisse un « vocabulaire critique » des pratiques artistiques qui n’ont pour approche, ni l’attitude fétichiste qui s’occupe des objets uniques (le « grand art »); ni à l’inverse, l’approche post-formaliste teintée de « nihilisme » qui consistent à proposer des « non-objets d’art », des artefacts d’œuvres dites conceptuelles (voulant malgré tout appartenir à l’ « histoire de l’art »). Ces pratiques « nouvelles », innomées donc informes sont difficilement défendables, Burnam les définit alors comme « systémiques » en vue de constituer un corps identifiable avec ses concepts propres. Dans la continuité de l’agitation des iconoclastes du début du XXeme siècle (faisant d’ailleurs référence à Duchamp) une perspective systémique ne considère pas la production d’entités matérielles comme unique moyen de création, mais, de façon beaucoup plus inclusive, s’attache aussi à la puissance relationnelle et didactique de potentiels objets. Ici, la notion d’ « objets » est entendu dans son sens le plus général, celui d’ « entités abstraites », celui d’élément ou de partie d’un ensemble, — qui seraient inclus dans ce système.

« Montrer que l’art ne consiste pas en entités matérielles, mais en relations entre les personnes ainsi qu’entre les personnes et leur environnement ». 1

En empruntant aux scientifiques la notion de « développement morphologique », il pose la notion de « système » comme un « complexe de composantes en interaction » qui se conceptualise tout d’abord au delà du cadre très spécifique des institutions artistiques, voyant par exemple dans les stratégies militaires, une forme d’art.

« La perspective des systèmes s’attache à la création de rapports stables, suivis, entre système organiques et non-organiques, que ce soient les quartiers, les complexes industriels, les fermes, les moyens de transport, les centres d’information, les centres de divertissement, ou toute autre matrice de l’activité humaine. »2

Dans ce cadre artistique, la « syntaxe visuelle » n’a plus l’exclusivité de la forme, la pratique analytique (les processus antérieurs à l’intégration de nouveaux objets dans la structure systémique ainsi que l’étude des relations qui unissent les différents éléments) est aussi considérée comme une forme en soi. Mais, d’une certaine manière, les idées sont des images, « il n’y a pas d’idées sans images ». Analyser, c’est tenter de modéliser, de structurer en diagramme des choses entre elles. Trouver les nœuds, tisser des liens. [Temps théorique, esthétique du graphe, de l’idée]

« Située entre des médias électroniques agressifs et deux cents ans de vandalisme industriel, l’idée longtemps répandue qu’une minuscule production d’objets d’art puisse en quelque manière « embellir » ou même modifier substantiellement l’environnement était naïve. Une illusion parallèle existait dans l’idée que l’influence artistique s’imposait par une osmose psychique dégagée par ses objets. En conséquence, l’intérêt de pure forme pour la beauté publique reste l’apanage de musées bien gardés. […] Dans une société si aliénée, seule la fonction didactique de l’art continue à avoir du sens. L’artiste opère comme un provocateur quasi-politique, même s’il n’est à aucun titre un idéologue ou un moraliste ».3

Le geste [politique] est un opérateur puissant au sein d’une pratique systémique, il est une action physique et symbolique qui prend corps dans une forme proche de la pratique théâtrale, sans se soucier de la légitimité de quelconque « proscenium ». Le geste n’est pas seulement un médium. (Comme au théâtre, il a son importance. Il y a sans doute au moins mille façons de traverser une scène, on traverse pour aller de A vers B, mais les propriétés de l’action « aller » ne sont pas négligeables, de la même façon qu’on ne regarde pas seulement pour voir. On ne regarde pas de la même manière sa copine ou son copain que le policier sévère qui effectue un contrôle d’alcoolémie – enfin je suppose).

Il y a des similarités entre ce qui s’apparenterait au domaine effectif d’un système et le point de vue de Brecht sur le théâtre qu’il considère d’ailleurs comme « un champ », un espace didactique qui veut se lier au réel, en contribuant au processus d’émancipation des acteurs et du public.

« Nous avons besoin d’un théâtre qui ne permette pas seulement les sensations, les aperçus et les impulsions qu’autorise à chaque fois le champ historique des relations humaines sur lequel les diverses actions se déroulent, mais qui emploie et engendre les idées et les sentiments qui jouent un rôle dans la transformation du champ lui-même. »4

En un sens, on pourrait considérer Brecht comme un « systématicien ». La science et les techniques, la « relativité historique », les questions sociales, les interactions entre l’ensemble de ses sujets et de ses représentants structurent « son » théâtre, l’argument d’un moment didactique. Ce moment didactique, lui, pourrait être considéré comme un système instable initialement, mais en voie de structuration. Le « gestus social » serait l’opération de stabilité qui permettrait de faire tendre la structure de nature systémique magmatique (incomplète, informe) vers un groupe de significations.

p55« […] les personnages s’injurient, se complimentent, s’instruisent l’un l’autre, etc. Au nombre des attitudes prises par des hommes les uns envers les autres, comptent même les attitudes en apparence entièrement privées, telles que les manifestations de la douleur physique dans la maladie ou les manifestations de religiosité. Ces manifestations gestuelles sont le plus souvent très complexes et pleines de contradictions, de sorte qu’il n’est plus possible de les rendre en un seul mot, et le comédien doit prendre garde, dans sa composition qui ne peut être qu’une amplification, de n’en rien perdre, mais au contraire d’amplifier l’ensemble tout entier. »5

Par ailleurs, ce n’est aussi pas un hasard si Jack Burnam s’inspire des scientifiques pour modéliser et généraliser des pratiques artistiques relationnelles, analytiques; Il cite notamment le biologiste Ludwig von Bertalanffy qui lui permet de définir un système comme un « complexe de composantes en interaction » en ajoutant que l’artiste-analyste « est un perspectiviste qui considère les buts, les frontières, la structure, la réception, la production et l’activité qui en dépend à l’intérieur et à l’extérieur du système ».

En effet, la notion de « système » peut -être rattachée à quelques théories scientifiques plus antérieures qui s’attachent à l’étude des relations entre des objets abstraits et des propriétés générales… Et c’est notamment le cas pour la puissante théorie mathématique des groupes. En reprenant les mots de Hermann Weyl, phycisien et mathématicien, l’approche systémique de Burnam ressemble à …

« … L’approche abstraite des groupes [qui] nous ouvre à une réalité mouvante en perpétuelle transformation, dans laquelle les choses sont des forces, la nature est comme un organisme, et les mathématiques, elles mêmes, une construction symbolique du monde »…6


1- Jack Burnam, « Esthétique des systèmes »
2-Gros ibid.
3-ibid. à bière
4-Bertod Brecht, « Petit organon pour le théâtre »
5-Ibid. dis donc
6-Benoit Timmermans, citation de Weyl, « Histoire philosophique de l’algèbre moderne ».

Cet article a été publié le 20 novembre 2016.

Envoyer des images ou des sons générées par Processing sur un serveur FTP

Cet article est issu d’un fil de discussion sur le forum codelab.fr que j’ai initié il y a quelques jours.

Voici un petit programme fait avec Processing.py. (j’ai choisi le mode python de Processing, pour utiliser la bibliothèque ftplib de python… peut-être y a t-il encore plus simple, m’enfin).
Il permet d’envoyer des images générées par Processing dans un dossier « img » sur un serveur FTP.
Également, avec un fichier php, nous pourrons afficher dynamiquement toutes les images contenues dans le dossier.

from ftplib import FTP
 
#INIT SKTECH
size(300, 300)
nom = str(day()) + str(month()) + str(hour()) + str(minute()) + ".png" # nom du fichier genere
 
#DESSIN
fill(random(255), random(255), random(255))
ellipse(random(width), random(height), 30, 30)
save(nom)
 
#CONNEXION changer variables
host = "ftp.******.fr"
user = "******"
password = "******"
connect = FTP(host, user, password)
#VERIF
etat = connect.getwelcome() # Envoi message de bienvenue si connection
print "etat connexion ftp ", etat
rep = connect.dir() # Affiche repertoires
print rep
 
#ENVOI
file = open(nom, 'rb')
connect.sendcmd('CWD www/exemple/img') # Commande FTP pour se placer dans un dossier precis. A modifier.
connect.storbinary('STOR ' + nom, file)
file.close()
 
#DECONNEXION et fermeture du programme.
connect.quit()
println("\nTermine !")
exit()

Voici un code .php très sommaire pour afficher toutes les images du dossier. Dans l’exemple, le fichier .php ainsi que le dossier contenant les images sont placé sur mon serveur dans « www/exemple ». À modifier selon vos besoins, évidemment ! :-)

<p>  
        <?php  
        $fichiers = glob('img/*');  
        foreach($fichiers as $i){  
          echo "<img class=\"img\" src=\"" . $i . "\">";  
        }  
        ?>  
</p>

Un autre exemple avec draw. C’est encore imparfait puisque l’animation se fige pendant l’envoi…

from ftplib import FTP
 
#envoie une image lorsqu'on appuie sur 'e'
 
def setup():
    size(300, 300)
    noStroke()
 
def draw():
    fill(random(255), random(255), random(255))
    ellipse(random(width), random(height), 30, 30)
    ellipse(mouseX, mouseY, 10, 10)
 
def keyReleased():
    if key == 'e':
        println("envoi")
        envoi()
 
def envoi():
    # On enregistre notre image.
    nom = str(day()) + str(month()) + str(hour()) + str(minute()) + str(second()) + ".jpg"
    save(nom)
    println(nom)
    #delay(1000) #un delay pour laisser le fichier s'ecrire tranquillement
 
    # On ouvre serveur, connexion, envoi.
    host = "******"
    user = "******"
    password = "******"
    connect = FTP(host, user, password)
    etat = connect.getwelcome()
    print "etat connexion ftp ", etat
    rep = connect.dir()
    print rep
 
    file = open(nom, 'rb')
    connect.sendcmd('CWD www/exemple/img')
    connect.storbinary('STOR ' + nom, file)
 
    file.close()
    println("debug file close")
    connect.quit()
    println("\nTermine !")

Avec ça, à titre d’exemple, j’ai générée et envoyé automatiquement sur l’internetosphère des déclinaisons d’un petit dessin simplet fait sous Processing.

http://www.completement.pt/exemple/

…Et ça marche aussi avec du son!
Toujours avec Processing.py, ci-dessous, un programme qui permet de lancer l’enregistrement d’un son avec un microphone (touche ‘r’), de cesser l’enregistrement (on rappuie sur ‘r’) puis de sauvegarder le fichier et de l’envoyer sur notre serveur (touche ‘s’); j’ai juste repris en Processing.py les exemples de la bibliothèque Minim…
C’est fait dans la perspective d’une installation interactive où les résultats générés par le dispositif serait archivés sur un site internet en quasi temps-réel, ou du moins automatiquement (bientôt j’espère des images du projet).

from ftplib import FTP
add_library('minim')
 
def setup():
    size(300, 300)
    global minim, input, recorder
    global nom
 
    minim = Minim(this)
    input = minim.getLineIn()
    nom = str(day()) + str(month()) + str(hour()) + str(minute()) + ".wav"
    recorder = minim.createRecorder(input, nom)
 
def draw():
    background(0)
    if recorder.isRecording():
        fill(0, 255, 0)
        println("enregistrement")
    else:
        fill(255)
 
    ellipse(width/2, height/2, 30, 30)
    envoi()
    delay(500)
 
def envoi():
    nom = str(day()) + str(month()) + str(hour()) + str(minute()) + str(second()) + ".png"
 
def keyReleased():
    if key == 'r':
        if recorder.isRecording():
            recorder.endRecord()
        else:
            recorder.beginRecord()
    if key == 's':
        recorder.save()
        println("sauve")
        execfile('envoi.py')
        println("envoyeee")

N’oublions pas envoi.py pour la connexion et l’envoi de fichier sur le serveur :

# coding: utf8
 
host = "***"
user = "***"
password = "***"
connect = FTP(host, user, password)
etat = connect.getwelcome()
print "etat connexion ftp ", etat
rep = connect.dir()
print rep
 
file = open(nom, 'rb')
connect.sendcmd('CWD www/exemple/son')
connect.storbinary('STOR ' + nom, file)
 
file.close()
println("debug file close")
connect.quit()
println("\nTermine !")

On reprend un peu notre fichier .php pour afficher nos fichiers sonores fraichement enregistrés…

<p>
        <h2>Sons</h2>
        <?php
        $fichiers = glob('son/*.wav');
        foreach($fichiers as $j){
          echo "<audio controls>";
          echo "<source src=\"" . $j . "\">" . "</audio>";
        }
        ?>
      </p>

C’est perfectible: le format .wav n’est sans doute pas le plus approprié pour le web. On pourrait bidouiller un petit quelque chose pour convertir le fichier en .mp3/.oggavant de l’envoyer sur le web.

Cet article a été publié le 21 janvier 2016.

Reconnaissance d’images #01

Toujours dans la série « germes de code », un petit exposé introductif à l’analyse et au traitement des images à des fins artichtiques. Dans l’article précédent, j’ai parlé de « donner la vue à l’image ». Cette idée suit son cours; aujourd’hui, on essaye de donner les moyens à l’ordinateur de reconnaitre une image dans un espace simple, statique. Bien qu’il existe des librairies de vision par ordinateur, tout ceci est fait pour la beauté (ou le plaisir) du geste. Cela nous permettra également d’avoir un tout petit aperçu des problèmes algorithmiques fort passionnants qui se poseront à propos de la vision par ordinateur.

Épisode 1: Reconnaissance stricte d’une image avec Processing

Nous voulons comparer deux images. La première est un modèle de référence, la seconde est donc l’image que l’on veut comparer.

Pour essayer l’algorithme de détection d’une image avec l’autre, nous allons commencer par programmer dans un espace statique, ou les différents espaces (taille de l’image 1, de l’image 2, et l’espace de calcul) sont strictement équivalents. Ainsi la taille du canevas est égal à l’image un qui est égale à l’image 2. Le programme n’effectuera qu’un unique tour de boucle. Nous voulons également retourner le taux de correspondance des deux images en pourcentage.

Pour la démonstration, nous allons utiliser tester l’algo avec différentes images.
1. L’image de référence dégradée légèrement avec du bruit
2. L’image de référence dégradée
3. L’image de référence très dégradée
4. L’image identique à l’image de référence
5. et évidemment l’image de référence que nous utiliserons à chaque fois.

bruite degrade degrade2 identique original

Comme nous ne comparerons seulement deux images à la fois (l’image référence et une image de test) nous n’allons déclarer que deux variables image (ou un tableau d’images, à votre guise). Nous commencerons par comparer l’image de référence avec son identique. Pour la comparaison, nous allons procéder de la façon suivante, très basiquement: nous allons comparer le premier pixel de la première image avec le premier pixel de la seconde image, puis le deuxième pixel de la première image avec le deuxième pixel de la seconde image et ainsi de suite… Si les deux valeurs correspondent, alors on ajoute 1 à une variable M, sinon tant pis. La variable N elle renvoie le nombre de pixels d’une image (les images ayant toutes la même résolution). Donc plus la valeur M se rapprochera de N, plus l’image de test ressemblera à notre image de référence.

Capture d’écran 2015-12-23 à 17.22.17

Ensuite, nous allons charger en mémoire tous les pixels de nos deux images, et comparer à chaque tour de boucle les pixels entre eux. Pour l’instant on vérifie si les couleurs des deux images sont strictement identiques.

Capture d’écran 2015-12-23 à 17.27.13

Ensuite, une petite règle de trois histoire de renvoyer le nombre de pixels en pourcentage ayant correspondu :

Capture d’écran 2015-12-23 à 17.29.51

Si on lance le programme on obtient en console un magnifique 100% si nos deux images sont identiques. Pour vérifier ça, on pourra pour chacune de nos deux variables PImage charger la même image.

Si on s’amuse à modifier (même un tout petit peu) l’image comparée (en modifiant un toutpetipetipeu la teinte par exemple), le programme retourne un violent 0%. Eh oui, ici, le programme juge de façon trop sévère, et si on voudra pousser le programmer plus loin (par exemple reconnaissance des images en passant par un système d’acquisition vidéo) eh bien on l’aura dans le baba.

Capture d’écran 2015-12-23 à 17.37.49

Jugez par vous-même: ces deux images vous semblent identiques? D’un certain point de vue elle le sont… Mais pour l’ordinateur, que dalle! En modifiant la teinte d’un rien (+2 sur GIMP) notre programme trouve encore à redire.

Pour rendre notre programme plus tolérant, on va dire qu’on ne s’intéressera seulement aux nuances, et plus aux couleurs qui ne font qu’ajouter des informations à contrôler.

FA_image_00027768

Ci-dessus, une image issue de la série « La Quatrième Dimension ». C’est en noir et blanc, et pourtant, on peut très bien distinguer les personnages, leur environnement et le notable tigre de Sibérie blanc sur le crâne d’un martien gris foncé en arrière-plan. Ceci est un argument pour souligner le fait que les informations colorimétriques ne sont forcément pas importantes pour distinguer des objets; j’espère que vous êtes convaincus.

Bien alors on ne va contrôler que la luminosité de nos pixels, on va juste ajuster la fonction brightness() lors dans la condition:

Capture d’écran 2015-12-23 à 17.49.47

Et là… Stupeur ! Ma console me dit que les couples de pixels correspondent à environ à 50%! On a laissé du mou, mais mon programme n’est pas encore au point. À ce stade, je pourrais à la louche espérer avoir un taux de correspondance proche de 100%. Et pourtant diantre. Alors on pourrait bidouiller un petit truc pas très élégant en laissant un seuil de jugement:

Capture d’écran 2015-12-23 à 17.55.41

Ici, j’ai ajouté une condition supplémentaire et un seuil de tolérance qui vaut 1 (j’ai donc déclaré plus haut dans mon programme une variable seuil valant 1) … Et ma console me dit effectivement que les images se ressemblent à 100%. Bon. Pas mal.

On a réussit à résoudre dans un premier temps un problème, mais ici, l’algorithme n’est pas assez costaud, on a vu que le moindre changement colorimétrique n’est pas considéré de façon raisonnable. Si on essaye le programme avec les autres images (voir plus haut), nous avons des résultats déplorables (j’ai 16% avec l’image légèrement bruité… Insuffisant). Dans la perspective de la création d’un détecteur d’image via un système d’acquisition vidéo, il nous faut une intelligence plus décontractée qui peut passer outre les déformations liées à la perspective, la différence colorimétrique, les interférences avec d’autres objets, la tolérance au bruit d’image, etc… Pour l’instant on est assez loin d’un algorithme ayant une « intelligence » satisfaisante, mais faisons les choses petit à petit. Allez, à bientôt pour l’épisode 2.

Ho, et sinon, il n’y avait donc pas de tigre de Sibérie sur la photo. Je suis un grand blagueur que voulez-vous. On est comme on est.

Cet article a été publié le 23 décembre 2015.

Processing: De l’image au son

Dans la série « jeu avec les pixels avec Processing » voici un petit billet concernant la génération de sons depuis une image. Comme dit dans un plus vieil article, je saute quelques étapes et je pars du principe que quelques notions basiques sont acquises. Je m’autorise quelques pauses « programmes-gadgets » avec Processing. Mais ces « gadgets » sont en fait, il me semble, les outils de bases parfaits pour apprendre et aussi commencer à développer des modules interactifs plus complets. Et d’ailleurs, si on a un tout petit peu d’imagination, ces petits programmes ont un fort potentiel…

Allez hop, on s’attaque aujourd’hui à un « grand classique » du design interactif: comment générer du son depuis la lecture d’une image ou d’un dessin, un peu comme l’UPIC de Xenakis ? Mais nous commencerons par la petite porte: on va juste générer des fréquences à partir des valeurs d’une image. Ci-dessous, une illustration de l’UPIC.

Dans cet article, nous allons décortiquer une méthode simple permettant dans un premier temps de lire et d’interpréter une image noir et blanc de façon linéaire. Bien que nous avons vu précédemment comment, grâce au frame differencing, enclencher un son grâce aux mouvement captés par la caméra, cette fois, il s’agira bien de générer du son (en langage pompeux: « interprétation sonore et algorithmique d’une image ») plutôt que d’activer ou contrôler une source sonore depuis une action comme un geste de la main.

Ci-dessous, voilà ce qu’on arrivera à faire à la fin de cet article, soit générer du son depuis une image. Rien de très gracieux ici, mais c’est voué à évoluer. J’ai également fait une petite variante du programme avec un code barre à la façon du Post Code de ::VTOL::, en beaucoup plus pauvre bien sûr; vous pourrez la voir ici.

C’est parti mon radis

Avant de commencer à coder, résumons ce que nous voulons. Premièrement, nous voulons générer des sons à partir d’informations relatives à une image, et plus précisément d’une parcelle de cette image. On pourra sélectionner la zone soit avec la souris, soit avec un curseur qui s’incrémente en abscisse ou en ordonnée. Cette zone pourra être fine (1 pixels) ou bien une zone plus large (disons 20px de largeur, et toute la hauteur de l’image). Cette zone générera un seul son.

Il y a plusieurs façon de synthétiser un son à partir de plusieurs informations. Ici, nous allons dire qu’on analyse les valeurs de gris (=luminosité) d’une parcelle de l’image, on compte toutes les valeurs (de 0 à 255) de tous les pixels et on en fait une moyenne. À cette moyenne, on lui faire subir une petite série d’opérations mathématiques afin qu’on puisse la transformer en valeur en Hertz assez acceptable pour être utilisée. Par exemple, si une zone nous donne 8, on va devoir trouver des petites formules pour que cette valeur soit plus grande. Eh oui, un rappel, la tranche audible des fréquences va d’environ 20Hz à 20000Hz. Et encore, ça dépend si on est fatigué ou si notre ordinateur est capable d’émettre des sons très graves ou très aigus.

Bien. On va décider qu’on veut faire notre bidouillage à partir d’une image. Bien, allez, on l’affiche.

Capture d’écran 2015-07-07 à 18.10.23

Magnifique. Maintenant, nous voulons définir notre curseur qui délimite la zone d’analyse de l’image. Cette « zone » récupère les informations de l’image, donc, nous allons balayer toute la « zone » avec pixels et compter leurs luminosité. Nous pourrons donc opter pour la méthode qui consiste à créer une deuxième image « cobaye », qui copie une portion de l’image au même endroit ou elle se situe (oui…). L’intérêt de faire une deuxième image plus petite est qu’on peut parcourir l’ensemble de l’image de 0 jusqu’à son maximum avec une simple boucle… ce qui nous permet de ne pas trop avoir à bricoler un truc avec des opérations mathématiques un brin plus avancées sur l’ensemble des pixels de notre canevas (pour en retenir qu’une parcelle, pas fabuleux). Et ça permet aussi de pouvoir, dans un contexte orienté objet, de multiplier ces zones (et donc les sons).

Oulà, bon regardons le code pour comprendre mieux (voir ci-dessous. J’ai copié un carré de l’image) Faites attention aux commentaires que j’ai laissé dans le code.

Capture d’écran 2015-07-07 à 18.46.35

decalage

Détails : Maintenant, on enlève le décalage de + 10 (et j’enlève les commentaires maintenant que vous avez pigé… je crois). Nos pixels copiés forme une deuxième couche identique à la première. Pour délimiter cette zone, je place un petit carré de la même taille et la même position (avec rect() évidemment). J’ai fait une petite fonction carré, parce que je suis propre. Mais faites ce que vous voulez, hein. Bon.

Désormais, nous allons faire des opérations sur les pixels pour déterminer la moyenne de la luminosité de ce morceau d’image. Allez un petit loadPixels() sur notre zone pour pouvoir récupérer les infos des pixels avec… pixels[]. Ah oui, il faut faire une petite boucle pour parcourir l’ensemble de nos pixels. Comme d’hab. Oui, voilà, un truc comme ça:

Capture d’écran 2015-07-07 à 19.19.07

À l’intérieur de la boucle, on va créer une variable locale de type color qui va récupérer les informations colorimétriques brutes de tous nos pixels (on veut récupérer un flux d’informations « brut » juste ici. Donc du local ça suffit). Ensuite on va déclarer une variable globale (donc utilisable partout dans le programme) qui va accumuler les informations filtrés avec brightness() de notre variable brute. On va extirper seulement les valeurs relatives à la luminosité. Et on va mettre à jour tout ce bazar avec un updatePixels() de notre zone. Voyez plutôt:

Capture d’écran 2015-07-07 à 19.27.48

Les deux dernières lignes de code de l’image ci-dessus, vous l’avez peut-être compris, c’est juste une bête moyenne et un affichage console de cette valeur. Si on déplace notre souris, on peut voir les valeurs fluctuer.

valeurs

Bien, le plus gros a été fait, et ça a été simple! Les valeurs vont de 0 à 255 maximum. La tranche de fréquence audible pour un être humain va de 20 à 20000Hz. Maintenant vous savez (ou vous sentez) que pour transformer ces valeurs qui vont de 0 à 255, on va faire une petite règle de trois avec la fonction map(). Évidemment, on créera une variable pour faire cela.

Pour le son, on utilisera la bibliothèque Minim. Bon, je reviens pas sur l’utilisation de Minim, je vous laisse plutôt le code complet. À télécharger ici ou à lire ci-dessous.

import ddf.minim.*;
import ddf.minim.ugens.*;Minim minim;
AudioOutput out;
Oscil wave;

PImage upic;
PImage zone;
float valeursNuances;
float toFrequence;

void setup() {
upic = loadImage(« upic.gif »);
size(upic.width, upic.height);

zone = createImage( 50, 50, RGB ); //Notre zone est un carré de 50*50

minim = new Minim(this);
out = minim.getLineOut();
wave = new Oscil (440, 0.5f, Waves.SINE);
wave.patch( out );
}

void draw() {
image(upic, 0, 0); // original
zone.copy( upic, mouseX, mouseY, 50, 50, 0, 0, 50, 50);//copié…

image(zone, mouseX, mouseY);//affiché
carre();

// Analyse de notre zone
zone.loadPixels();
for (int i = 0; i < zone.pixels.length; i++){ color valeursBrutesPixels = zone.pixels[i]; valeursNuances += brightness(valeursBrutesPixels); } //zone.updatePixels(); //pas utile en fait valeursNuances = (float) valeursNuances / ( 50 * 50 ); toFrequence = map(valeursNuances, 0, 255, 20, 20000); //println(toFrequence); wave.setFrequency(toFrequence); } void carre(){ noFill(); stroke(255,255,0); rect(mouseX, mouseY, 50, 50); }

L’étape supérieure serait de pouvoir gérer la lecture d’images en couleurs depuis un flux webcam avec par exemple, un tête de lecture automatisée. On pourrait faire un synthétiseur ou un loopeur contrôlé avec une feuille blanche et des feutres.

Cet article a été publié le 7 juillet 2015.

« Frame differencing » avec Processing (round 2)

Dans l’article précédent, j’expliquais comment « quantifier » un mouvement capturé par une caméra. Par quantifier je veux dire analyser comparer deux images successives d’un flux vidéo, l’une étant celle de l’instant T présent, l’autre de l’instant T – 1 passé. Par « quantifier » je veux dire calculer les différences colorimétriques de ces deux images et ainsi deviner qu’il y a eu un changement, par exemple issu d’un mouvement de main ou d’un déplacement de caméra. Dans cet article, j’ai un peu amélioré le programme, tout en le condensant davantage.
Ci-dessous, un petit programme qui utilise le frame differencing pour activer du son.

Dans le domaine de la vision numérique, j’avais lu plus tôt que les nombreux algorithmes de détection (de contours, de fond, de visage…) ne se basent pas sur des images colorées RVB mais bien sur la luminosité d’une image. Les informations noir et blanc suffisent, et sont moins lourdes à exécuter. En prenant compte de cela, j’ai changé à l’intérieur de la boucle du code :

color present = cam.pixels[i];
color passe = imagePasse.pixels[i];

float rougePresent = red(present);
float vertPresent = green(present);
float bleuPresent = blue(present);

float rougePasse = red(passe);
float vertPasse = green(passe);
float bleuPasse = blue(passe);

float diff = dist(rougePresent, vertPresent, bleuPresent, rougePasse, vertPasse, bleuPasse);

par:

color present = cam.pixels[i];
color passe = imagePrec.pixels[i];

float lumPresent = brightness(present);
float lumPasse = brightness(passe);

float diff = dist(lumPresent, lumPresent, lumPasse, lumPasse);

C’est quand même plus conçis comme ça.

J’ai également ajouté un seuil de sensibilité qui ne prend pas en compte des petits changements bénins de la capture (le bruit d’image) avec une bête condition qui dit « si le taux de changement est inférieur à la variable seuil, alors autant ignorer cette différence »:

if(diff < seuil){ diff = 0; }

J’ai déclaré ma variable seuil à 15 dans l’en-tête de mon programme.

Également, j’ai remarqué que l’animation qui représentait la quantité de mouvement de la capture était un peu frénétique; Pour supprimer ces sauts brutaux et « lisser » un peu l’animation, je suis passé par une petite moyenne pondérée (merci au Mooc du CNAM) que voici:

Capture d’écran 2015-06-28 à 12.20.03

Et ça me fait quelque chose comme ça (j’ai déclaré mon variable alpha en haut du programme. J’ai mis sa valeur à 0.5, à vous de voir ce qui vous arrange):

float moyenneMouvement = mouvement/cam.pixels.length;
r = (1 – alpha) * moyenneMouvement + alpha * r; //adoucit l’animation

À alpha = 0, notre animation n’est pas adoucie, et la réaction est immédiate.
À alpha = 0.9 notre animation est très adoucie, mais il y a du retard et peu de sensibilité.

Et voilà ci-dessous le code complet ou bien à télécharger ici.

import processing.video.*;

Capture cam;
int seuil = 15;
PImage imagePrec;

float alpha = 0.4;
float r = 0;

void setup(){
size(320, 240);
cam = new Capture(this, 320, 240);
cam.start();
imagePrec = createImage(width, height, RGB);
}

void captureEvent(Capture cam){
cam.read();
}

void draw(){
background(0);
image(cam, 0, 0);

imagePrec.copy(cam, 0, 0, width, height, 0, 0, width, height);
float mouvement = 0;

cam.loadPixels();
imagePrec.loadPixels();
for(int i = 0; i < cam.pixels.length; i++){ color present = cam.pixels[i]; color passe = imagePrec.pixels[i]; float lumPresent = brightness(present); float lumPasse = brightness(passe); float diff = dist(lumPresent, lumPresent, lumPasse, lumPasse); if(diff < seuil){ diff = 0; } mouvement += diff; } float moyenneMouvement = mouvement/cam.pixels.length; r = (1 - alpha) * moyenneMouvement + alpha * r; ellipse(width/2,height/2,r*2,r*2); }

EDIT : voici le .zip d’un programme qui permet de déclencher du son au mouvement. Hop! Cadeau!

Cet article a été publié le 28 juin 2015.
Page suivante »