Mon Raspberry Pi, c’est mon petit passe-temps quand j’en ai marre de bosser. Mais tout de même, je me rassure en me disant que quand je fais du développement sur le Pi, ça me fait découvrir des trucs divers et variés.
Pour le coup, je suis encore sur ma détection / suivi de mouvement utilisant la Camera Board. L’algorithme général est pas bien compliqué :
- Acquérir l’image n-2 et la convertir
- Acquérir l’image n-1 et la convertir
- Acquérir l’image n et la convertir
- Comparer les images n-2 et n-1
- Comparer les images n-1 et n
- Déduire des deux étapes précédentes s’il y a eu un mouvement
- Centrer la caméra vers le mouvement
- Sauvegarder les images pertinentes sur le réseau
- Renommer n-1 en n-2 et n en n-1
- Boucler à l’étape 3
L’étape 7 est faite avec un script en python, les étapes 4, 5 et 6 faites avec un soft en C, le reste, c’est du bash script. Le script générant des fichiers régulièrement, je le fais tourner dans un ramdisk histoire de ne pas pourrir ma flash.
L’idée, c’est d’optimiser un peu le concept. Première piste que j’ai suivi, c’est de lancer en arrière-plan les différentes copies et renommage de fichier lorsque que ça pouvait être fait (genre l’étape 8, mais pas la neuf). En bash c’est pas bien compliqué, suffit de rajouter un « & » à la fin de la ligne. De même, le lancement du script python pour faire pivoter la caméra, je me fous pas mal d’attendre que le mouvement ce termine.
Puis, je me suis mis en tête de mesurer le temps d’exécution du soft en C, qui pour rappel prends 3 images en entrée, et me sort 3 images en sortie (diff entre n-2 et n-1, diff entre n-2 et le mouvement résultant). J’ai pris le timestamp au démarrage du soft et à la fin, une différence entre les 2, un printf, un boucle réalisant 100 fois l’opération histoire de faire un peu de stat’.
Ayant développé l’appli sur un PC, j’ai donc eu comme première mesure moyenne 99ms pour réaliser l’opération (sur un Core i7 3520M @ 2,9GHz), que j’ai ensuite refait sur le Pi à partir de la flash, et j’ai eu 597ms de moyenne (sur un Raspberry Pi 256Mo @ 700MHz). Alors oui… ça fait beaucoup. Puis test en ramdisk, et j’ai eu la surprise de voir que le temps moyen, 624ms est plus élevé qu’en flash ! Je n’ai pas encore compris pourquoi, il faudra que je vois s’il n’y pas une merde dans ma config de ramdisk.
En étant bête et con, j’ai ensuite overclocké le Pi avec l’outil de config fourni avec (raspi-config) à 1GHz. Résultat en flash : 477ms, et en ramdisk 478ms. Conclusion partielle, avec un overclock de 43%, je gagne 23% de perf. Bon, c’est toujours ça de pris.
Enfin, un peu plus malin, j’ai testé de compiler mon soft avec l’option d’optimisation de GCC (gcc -Ox source.c -o mon_exe), qui propose 5 niveaux de vitesse et une optimisation en taille. J’ai gardé l’overclock par flemme de redémarrer le R-Pi, et j’ai fait tourner l’appli en flash. Les résultats oscillent entre 354ms et 328ms, respectivement pour l’optimisation en taille et l’optimisation de niveau trois (-O3).
Avec un overclock et une option en plus dans GCC, je suis donc passé de 597 à 328ms 45% de temps en moins. L’air de rien, c’est pas si mal et ne m’a demandé aucun effort intellectuel d’optimisation de code.
Résumé des différents essais :
Au final, j’ai surtout tenté d’améliorer le temps d’exécution de la comparaison d’image. Mais il y a d’autres points qui pourraient être abordé :
- Pouvoir lancer des commandes en fond dans le shell script en étant sur que leurs résultats seront prêts quand j’en aurai besoin
- La comparaison d’image se fait en comparant les images pixels par pixels et couleur par couleurs (une boucle « for » avec 3 comparaisons dedans). Bien que le Rpi soit mono-coeur, peut être qu’on pourrait tenter de paralléliser ces comparaisons, ou bien de ne faire qu’une seule couleur
- Vérifier que la partie « conversion d’image » est optimal. Pour le moment, je fais une capture en JPG, convertie ensuite et redimensionner en bmp (avec un rapport x16 entre les deux, permettant de créer la miniature bmp en sous échantillonnant les pixels de l’image capturé)
Et pour terminer, vérifier régulièrement que le truc marche encore après toutes ces bidouilles !