Dans cet article, on va récupérer les pixels de la caméra et les transmettre composante par composante (rouge, vert, bleu) à un ordinateur pour afficher l’image.
Bien entendu ce n’est pas l’utilisation principale de cette caméra, car le débit est très lent, mais cela permet de visualiser ce que voit la caméra, pour détecter une erreur dans notre programme embarqué ou pour tester les éclairages auxquels un robot peut être soumis, avec tous les aléas que cela comprend.
Préparation
Un peu de réflexion pour commencer. L’image fait 160 pixels de large sur 120 pixels de hauteur. On va donc recevoir 19200 pixels avec une communication série à 115200 bits par seconde soit 14 400 octets par seconde. On peut donc déjà s’apercevoir qu’il faudra plus d’une seconde pour recevoir l’image.
La caméra Pob-Eye 2 permet de récupérer deux types d’images : compressée ou non compressée. Avec la compression, on utilise 1 octet par pixel, et chaque couleur peut recevoir 2 (bleu) ou 3 bits (rouge et vert). Autant dire que le nombre de couleurs est limité (256 en toute logique).
Code source
Code Pob-Eye 2
Voici le code pour la caméra (ARM7 + code Pob-Tools) qui n’est pas optimal (conversion en 3 octets alors que toute l’information utile tient dans un seul) mais il fonctionne.
#include <pob-eye.h>
int main(void)
UInt32 i ;
UInt8 *rgbFrame ;
UInt8 r,g,b ;
// initialisation obligatoires
InitPobeye2() ;
InitUART0(115200) ;
InitI2C(I2C_100_KHZ) ;
InitCameraPobeye2() ;
// déclaration d’une frame RGB (19200 bytes)
rgbFrame = GetRGBFrame() ;
while(1)
// attente d’un caractère sur la liaison série.. ’clic’ :)
GetByteFromUART0() ;
// prendre la photo
GrabRGBFrame() ;
// envoyer pixel par pixel, composante par composante
for(i = 0 ; i < WIDTH_FRAME * HEIGHT_FRAME ; i++)
r = GetRed(rgbFrame[i]) ;
g = GetGreen(rgbFrame[i]) ;
b = GetBlue(rgbFrame[i]) ;
// avec retour à la ligne pour faciliter les corrections
PrintToUart0("%c%c%c\n",r,g,b) ;
return 0 ;
Code Processing
A copier dans un nouveau sketch pour Processing (testé avec version 1.0.6). Il suffit de taper une touche au clavier dans la petite fenêtre grise pour lancer une acquisition.
import processing.serial.* ;
Serial port ;
int index = 0 ;
color c ;
void setup()
size(160,120) ;
//
port = new Serial(this, Serial.list()[1], 115200) ;
// ne démarrer le traitement d’une trame
// qu’après réception du caractère fin de ligne (10 = \n)
port.bufferUntil(10) ;
void keyPressed()
loadPixels() ;
// déclencher la photo
port.write("p") ;
index = 0 ;
void serialEvent(Serial p)
if (index < width*height)
int r = port.readChar() ;
int g = port.readChar() ;
int b = port.readChar() ;
if (r < 256 && g < 256 && b < 256)
c = color(r, g, b) ;
int linefeed = port.readChar() ;
pixels[index++] = c ;
updatePixels() ;
else
println("OK") ;
void draw()
Le résultat
Pour aller plus loin
Preuve que cet exercice est utile, vous allez comprendre la raison du test "if (r < 256 && ...". Grâce à ce "dump" de l’image, on s’aperçoit qu’on peut avoir une valeur incorrecte pour des pixels trop brillants ou trop sombres, ce qui se caractérise dans l’image ci-jointe par une couleur turquoise.
Si ce problème n’est pas détecté, les traitements d’image peuvent être totalement incohérents : il est donc utile de faire une capture régulière en conditions réelles, y compris pour un robot testé de nombreuses fois sans erreur en atelier, et la contrôler de visu.