<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
>

<channel>
	<title>Association Qu&#233;b&#233;coise de Robotique Amateur</title>
	<link>http://www.aqra.ca/</link>
	<description></description>
	<language>fr</language>
	<generator>SPIP - www.spip.net</generator>



	



	<item>
		<title>&#201;tude comparative des algorithmes de connexit&#233; appliqu&#233;s &#224; la d&#233;tection de r&#233;gions dans une image</title>
		<link>http://aqra.ca/Etude-comparative-des-algorithmes</link>
		<guid isPermaLink="true">http://aqra.ca/Etude-comparative-des-algorithmes</guid>
		<dc:date>2009-03-15T00:45:32Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Pierre-Luc Bacon</dc:creator>

<category domain="http://aqra.ca/-Programmation-">Programmation</category>


		<description>Ce projet a &#233;t&#233; r&#233;alis&#233; en 2008 alors que d&#233;veloppant l'algo de vision pour le robot, je r&#233;alisais &#233;galement un travail d'analyse pour tenter de d&#233;terminer la meilleure approche &#224; adopter pour ce probl&#232;me. Les r&#233;sultats de mes recherches ont &#233;t&#233; rassembl&#233;s dans ce document qui a &#233;t&#233; propos&#233; en &quot;travail de fin d'&#233;tudes&quot; au C&#201;GEP. &lt;br /&gt;Ce document pr&#233;sente les r&#233;sultats d'une &#233;tude comparative visant &#224; d&#233;terminer l'efficacit&#233; d'une implantation r&#233;elle d'algorithmes servant &#224; l'extraction des r&#233;gions d'int&#233;r&#234;t d'apr&#232;s (...)


-
&lt;a href="http://aqra.ca/-Programmation-" rel="directory"&gt;Programmation&lt;/a&gt;


		</description>


 <content:encoded>&lt;img src=&quot;http://aqra.ca/IMG/arton88.png&quot; alt=&quot;&quot; align=&quot;right&quot; width=&quot;962&quot; height=&quot;570&quot; class=&quot;spip_logos&quot; /&gt;
		&lt;div class='rss_chapo'&gt;Ce projet a &#233;t&#233; r&#233;alis&#233; en 2008 alors que d&#233;veloppant l'algo de vision pour le robot, je r&#233;alisais &#233;galement un travail d'analyse pour tenter de d&#233;terminer la meilleure approche &#224; adopter pour ce probl&#232;me. Les r&#233;sultats de mes recherches ont &#233;t&#233; rassembl&#233;s dans ce document qui a &#233;t&#233; propos&#233; en &quot;travail de fin d'&#233;tudes&quot; au &lt;a href=&quot;http://fr.wikipedia.org/wiki/C%C3%A9gep&quot; class=&quot;spip_out&quot;&gt;C&#201;GEP&lt;/a&gt;.&lt;/div&gt;
		&lt;div class='rss_texte'&gt;&lt;p class=&quot;spip&quot;&gt;&lt;i class=&quot;spip&quot;&gt;Ce document pr&#233;sente les r&#233;sultats d'une &#233;tude comparative visant &#224; d&#233;terminer l'efficacit&#233; d'une implantation r&#233;elle d'algorithmes servant &#224; l'extraction des r&#233;gions d'int&#233;r&#234;t d'apr&#232;s les composants connect&#233;s d'une image. Nous nous int&#233;ressons plus en d&#233;tails aux techniques d&#233;velopp&#233;es par Bruce et al. (2000) ainsi que (Wu et al., 2005) qui sont toutes deux caract&#233;ris&#233;es par une complexit&#233; en temps lin&#233;aire &lt;i class=&quot;spip&quot;&gt;O(n)&lt;/i&gt;. Une approche th&#233;orique permettra d'abord de pr&#233;ciser les caract&#233;ristiques th&#233;oriques de quelques techniques d&#233;velopp&#233;es pour solutionner ce probl&#232;me alors que des essais pratiques metteront ensuite en lumi&#232;re leur temps d'ex&#233;cution.&lt;/i&gt;&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;L'article en question est t&#233;l&#233;chargeable au bas de cette page.&lt;/p&gt;&lt;/div&gt;
		
		</content:encoded>


		
		<enclosure url="http://aqra.ca/IMG/pdf_affiche.pdf" length="1334247" type="application/pdf" />
		
		<enclosure url="http://aqra.ca/IMG/pdf_baconEtudeComparative-2008.pdf" length="1972397" type="application/pdf" />
		

	</item>



	<item>
		<title>&#201;tiquetage des composants connect&#233;s et segmentation des couleurs avec CMVision 1.2</title>
		<link>http://aqra.ca/Etiquetage-des-composants</link>
		<guid isPermaLink="true">http://aqra.ca/Etiquetage-des-composants</guid>
		<dc:date>2009-03-15T00:18:20Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Pierre-Luc Bacon</dc:creator>

<category domain="http://aqra.ca/-Programmation-">Programmation</category>


		<description>Toute &#233;quipe qui doit embarquer une cam&#233;ra sur son robot doit le faire &#224; tout coup. Implanter un algorithme effiace d'&#233;tiquetage des r&#233;gions de couleurs (aka &quot;connected component labeling&quot;) est souvent une &#233;tape complexe qui, si mal r&#233;alis&#233;e peu entra&#238;ner des d&#233;lais de traitement beaucoup trop important. Un choix s'impose alors : tenter une solution &quot;maison&quot; ou utiliser une solution libre d&#233;j&#224; disponible. &lt;br /&gt;OpenCV est souvent choisi dans ce cas. Bien que tr&#232;s perfectionn&#233;e, OpenCV a peut-&#234;tre trop &#224; (...)


-
&lt;a href="http://aqra.ca/-Programmation-" rel="directory"&gt;Programmation&lt;/a&gt;


		</description>


 <content:encoded>&lt;img src=&quot;http://aqra.ca/IMG/arton87.png&quot; alt=&quot;&quot; align=&quot;right&quot; width=&quot;320&quot; height=&quot;240&quot; class=&quot;spip_logos&quot; /&gt;
		&lt;div class='rss_chapo'&gt;Toute &#233;quipe qui doit embarquer une cam&#233;ra sur son robot doit le faire &#224; tout coup. Implanter un algorithme effiace d'&#233;tiquetage des r&#233;gions de couleurs (aka &quot;connected component labeling&quot;) est souvent une &#233;tape complexe qui, si mal r&#233;alis&#233;e peu entra&#238;ner des d&#233;lais de traitement beaucoup trop important. Un choix s'impose alors : tenter une solution &quot;maison&quot; ou utiliser une solution libre d&#233;j&#224; disponible.&lt;/div&gt;
		&lt;div class='rss_texte'&gt;&lt;p class=&quot;spip&quot;&gt;OpenCV est souvent choisi dans ce cas. Bien que tr&#232;s perfectionn&#233;e, OpenCV a peut-&#234;tre trop &#224; offrir quand vient le temps d'implanter une solution simple pour un syst&#232;me aux ressources limit&#233;es.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;&lt;a href=&quot;http://www.cs.cmu.edu/~jbruce/cmvision/&quot; class=&quot;spip_out&quot;&gt;CMVision&lt;/a&gt; (c++) s'av&#232;re &#234;tre un choix tout indiqu&#233; pour r&#233;pondre au besoin pr&#233;cis d'&#233;tiquetage des r&#233;gions de couleurs. R&#233;alis&#233; par des &#233;tudiants du &lt;a href=&quot;http://www.cs.cmu.edu/~jbruce/cmvision/papers/CMVision-IROS2000.pdf&quot; class=&quot;spip_out&quot;&gt;MIT&lt;/a&gt; dans le cadre de Robocup, cette librairie utilise plusieurs algorithmes performants pour r&#233;aliser cette op&#233;ration. Les couleurs sont d'abord d&#233;tect&#233;es par un algorithme de seuillage ordinaire &#224; la diff&#233;rence pr&#232;s qu'une astuce permet de d&#233;terminer si un pixel appartient &#224; une classe de couleur (jusqu'&#224; 32) en une seule op&#233;ration binaire plut&#244;t qu'en proc&#233;dant &#224; 6 comparaisons logiques requises par l'approche &quot;na&#239;ve&quot;. L'image seuill&#233;e est ensuite encod&#233;e en &lt;a href=&quot;http://en.wikipedia.org/wiki/Run-length_encoding&quot; class=&quot;spip_out&quot; title=&quot;Run Length Encoding&quot;&gt;s&#233;ries de pixels adjacents&lt;/a&gt; et analys&#233;e dans un algorithme de type &lt;a href=&quot;http://en.wikipedia.org/wiki/Disjoint-set_data_structure&quot; class=&quot;spip_out&quot;&gt;Union- Find&lt;/a&gt; implant&#233; sous forme de listes cha&#238;n&#233;es.&lt;/p&gt; &lt;h2&gt;Utilisation&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Un seul constructeur est fourni dans la version 1.2 pour un objet de type &quot;CMVision&quot;.&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='1' class='spip_cadre' dir='ltr'&gt;CMVision vis;&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;L'utilisateur devra ensuite fournir d'autres param&#232;tres d'initialisation manuellement :&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='1' class='spip_cadre' dir='ltr'&gt;bool initialize(int nwidth,int nheight);&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;et&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='1' class='spip_cadre' dir='ltr'&gt;bool loadOptions(char *filename);&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;Ces m&#233;thodes sont celles qui devront le plus souvent &#234;tre appel&#233;es. loadOptions() prend en argument le nom d'un fichier qui contient une liste de seuils pour chacune des couleurs &#224; d&#233;tecter. Il est format&#233; comme suit :&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='5' class='spip_cadre' dir='ltr'&gt;[Colors] (255,0, 0) 0.000000 Ball [Thresholds] (100:230, 10:100, 10:130)&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;La section &quot;colors&quot; contient le triplet RGB associ&#233; &#224; la couleur (utile pour le debugging ou pour la partie GUI), la valeur &quot;merge&quot; (non utilis&#233;e ici), et un identifiant texte. La section threshold contient quand &#224; elle les seuils &lt;i class=&quot;spip&quot;&gt;min&lt;/i&gt; et &lt;i class=&quot;spip&quot;&gt;max&lt;/i&gt; pour chacun des 3 canaux de couleur.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Une fois ces quelques m&#233;thodes execut&#233;es, nous sommes d&#233;j&#224; en mesure d'effectuer le traitement sur l'image :&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='1' class='spip_cadre' dir='ltr'&gt;vis.processFrame(buffer);&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;Cette m&#233;thode est surcharg&#233;e pour supporter plusieurs arrangement en m&#233;moire possibles de l'image :&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='3' class='spip_cadre' dir='ltr'&gt;bool processFrame(image_pixel *image); bool processFrame(unsigned *map); bool processFrame(unsigned char *image);&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;o&#249; &lt;i class=&quot;spip&quot;&gt;image_pixel&lt;/i&gt; est un format pr&#233;-d&#233;fini dans cmvision.h qui, selon le &quot;define&quot; utilis&#233; au moment de la compilation, sera d&#233;fini comme une de ces structures :&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='11' class='spip_cadre' dir='ltr'&gt;struct yuv{ unsigned char y,u,v; }; struct yuv422{ unsigned char y1,u,y2,v; }; struct uyvy{ unsigned char u,y1,v,y2; };&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;Dans la plupart des applications, il sera plus simple de fournir une image de type &quot;unsigned&quot; o&#249; chaque pixel est d&#233;fini un apr&#232;s l'autre par 3 valeurs de canaux cons&#233;cutives. &lt;/cadre&gt;&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Si l'image contient un certains nombre de r&#233;gions de couleurs tel que pr&#233;cis&#233; dans le fichier de configuration, getRegions() permettra de les acqu&#233;rir via un pointeur de type &quot;region&quot;.&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='1' class='spip_cadre' dir='ltr'&gt;region *getRegions(int color_id);&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;o&#249; color_id et le num&#233;ro associ&#233; &#224; la couleur d&#233;finie dans le fichier de configuration (la num&#233;ration est automatique par ordre de d&#233;finition).&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='1' class='spip_cadre' dir='ltr'&gt;int numRegions(int color_id);&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;indiquera le nombre de r&#233;gions d&#233;tect&#233;es.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Le type &lt;i class=&quot;spip&quot;&gt;r&#233;gion&lt;/i&gt; est d&#233;fini ainsi :&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='14' class='spip_cadre' dir='ltr'&gt;struct region{ int color; // id of the color int area; // occupied area in pixels int x1,y1,x2,y2; // bounding box (x1,y1) - (x2,y2) float cen_x,cen_y; // centroid yuv average; // average color (if CMV_COLOR_AVERAGES enabled) int sum_x,sum_y,sum_z; // temporaries for centroid and avg color // int area_check; // DEBUG ONLY region *next; // next region in list // int number; // DEBUG ONLY };&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;Connaissant le nombre de couleurs ainsi que le nombre de r&#233;gions d'apr&#232;s numRegions(). nous pourrions alors ex&#233;cuter une boucle pour afficher les informations de la structure &quot;region&quot; pour chaque composant d&#233;tect&#233;.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Finalement,&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='1' class='spip_cadre' dir='ltr'&gt;void writeColorMap(const std::string &amp;name);&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;peut s'av&#233;rer utile pour visualiser les pixels d&#233;tect&#233;s dans la phase de seuillage. Un fichier ppm sera alors cr&#233;&#233; o&#249; chaque pixel prendra la valeur de son identifiant de couleur.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Il n'existe pas de documentation officielle pour la librairie CMVision-1.2. Ainsi, les m&#233;thodes pr&#233;sent&#233;es ici ne repr&#233;sentent pas r&#233;ellement toutes celles disponibles. La lecture de cmvision.h suffira bien souvent pour comprendre le fonctionnement de ces autres m&#233;thodes.&lt;/p&gt; &lt;h2&gt;Exemple&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;&lt;span class='spip_document_642 spip_documents spip_documents_center' &gt; &lt;img src='http://aqra.ca/IMG/cache-502x502/png_Screenshot-Eurobot_2008_Calibration-1-502x502.png' width='502' height='502' alt=&quot;&quot; /&gt;
&lt;/span&gt;
L'exemple suivant utilise les m&#233;thodes d&#233;crites plus haut de CMVision-1.2, la classe &lt;a href=&quot;http://www.aqra.ca/Capture-d-images-avec-Video-For&quot; class=&quot;spip_out&quot; title=&quot;VideoInput&quot;&gt;VideoInput&lt;/a&gt;, ainsi que les librairies &lt;a href=&quot;http://www.libsdl.org/&quot; class=&quot;spip_out&quot; title=&quot;libsdl&quot;&gt;SDL&lt;/a&gt; et &lt;a href=&quot;http://www.ferzkopp.net/joomla/content/view/19/14/&quot; class=&quot;spip_out&quot; title=&quot;libsdl-gfx&quot;&gt;SDL-gfx&lt;/a&gt; (sudo apt-get install libsdl-gfx1.2-dev).&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Une fen&#234;tre SDL affichera en temps r&#233;el les images captur&#233;es par la cam&#233;ra, les pixels seuill&#233;s, et les r&#233;gions d'int&#233;r&#234;ts d&#233;tect&#233;es.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Le code de ce programme est disponible au bas de cette page. Pour le compiler, il suffira d'ex&#233;cuter &quot;make&quot; dans le dossier cr&#233;&#233; apr&#232;s d&#233;compression de l'archive.&lt;/p&gt;&lt;/div&gt;
		
		</content:encoded>


		
		<enclosure url="http://aqra.ca/IMG/bz2/cmvision-example-baconPierreLuc.tar.bz2" length="16747" type="application/x-bzip2" />
		

	</item>



	<item>
		<title>Port s&#233;rie en C sous Linux</title>
		<link>http://aqra.ca/Port-serie-en-C-sous-Linux</link>
		<guid isPermaLink="true">http://aqra.ca/Port-serie-en-C-sous-Linux</guid>
		<dc:date>2007-06-14T22:26:08Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Pierre-Luc Bacon</dc:creator>

<category domain="http://aqra.ca/-Programmation-">Programmation</category>


		<description>Sommaire &lt;br /&gt;Le port parall&#232;le peut semble plus simple &#224; utiliser &#224; bien des &#233;gards quand vient le temps d&#233;terminer l'interface de communication avec un robot. Toutefois, celui-ci est appel&#233; &#224; dispara&#238;tre sur le nouveau mat&#233;riel et est bien souvent absent des cartes m&#232;res embarqu&#233;es (single board computer). Certes, il en est de m&#234;me pour le port s&#233;rie, mais les adapteurs usb/s&#233;rie sont tr&#232;s faciles &#224; trouver. Notons ici que FTDI Chip produit le FT245 ; FT245 qui permet d'obtenir une liaison parall&#232;le virtuelle (...)


-
&lt;a href="http://aqra.ca/-Programmation-" rel="directory"&gt;Programmation&lt;/a&gt;


		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;h2&gt;Sommaire&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Le port parall&#232;le peut semble plus simple &#224; utiliser &#224; bien des &#233;gards quand vient le temps d&#233;terminer l'interface de communication avec un robot. Toutefois, celui-ci est appel&#233; &#224; dispara&#238;tre sur le nouveau mat&#233;riel et est bien souvent absent des cartes m&#232;res embarqu&#233;es (single board computer). Certes, il en est de m&#234;me pour le port s&#233;rie, mais les adapteurs usb/s&#233;rie sont tr&#232;s faciles &#224; trouver. Notons ici que FTDI Chip produit le &lt;a href=&quot;http://www.ftdichip.com/Products/FT245R.htm&quot; class=&quot;spip_out&quot; title=&quot;FT245&quot;&gt;FT245&lt;/a&gt; qui permet d'obtenir une liaison parall&#232;le virtuelle au travers d'un port USB.&lt;/p&gt; &lt;h2&gt;Ouverture et fermeture du port&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Les fonctions qui permettent de r&#233;aliser ces op&#233;rations sont les m&#234;mes que celles utilis&#233;es courament dans les syst&#232;mes UNIX : open() et close() serviront donc, vous l'aurez devin&#233;.&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='9' class='spip_cadre' dir='ltr'&gt;int srl_handle; srl_handle=open(&quot;/dev/ttyUSB0&quot;, O_RDWR | O_NOCTTY | O_NDELAY); if(srl_handle&amp;lt;0) { perror(&quot;serial port open&quot;); exit(-1); }else { fcntl(srl_handle,F_SETFL,0); }&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;Vous aurez ici remarqu&#233; que &lt;strong class=&quot;spip&quot;&gt;/dev/ttyUSB0&lt;/strong&gt; est pass&#233; &#224; la fonction open() plut&#244;t que &lt;strong class=&quot;spip&quot;&gt;/dev/ttyS0&lt;/strong&gt;. Ceci n'est applicable que si la notation retenue dans udev pour un adapteur usb/s&#233;rie est sous cette forme. Voyez &lt;strong class=&quot;spip&quot;&gt;dmesg&lt;/strong&gt; apr&#232;s branchement pour plus de d&#233;tails. M&#234;me si la liaison RS232 s'effectue par USB, l'interface de programmation ne change pas : le driver se charge de rendre opaque les d&#233;tails d'impl&#233;mentation USB.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;O_NOCTTY est une option permettant de sp&#233;cifier que le programme ne sera pas un &quot;&lt;i class=&quot;spip&quot;&gt;controlling terminal&lt;/i&gt;&quot; : un param&#232;tre pass&#233; presque &#224; tout coup pour la plupart des programmes.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;O_RDWR signifie que le fichier est ouvert en lecture et en &#233;criture.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;O_NDELAY sp&#233;cifie finalement de ne pas attendre un changement de ligne sur le signal DCD. Si cette option n'est pas pass&#233;e, le programme sera bloqu&#233; jusqu'&#224; ce que DCD passe &#224; l'&#233;tat bas.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;La fonction fcntl est quant &#224; elle appel&#233;e pour permettre de r&#233;tablir le port s&#233;rie en mode bloquant pour la fonction read(). Ainsi, si aucun charact&#232;re n'est encore disponible en lecture, le programme attendra en ce point du programme.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;La fermeture du port se fait avec la fonction close(), tout simplement :&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='1' class='spip_cadre' dir='ltr'&gt;close(srl_handle);&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt;
&lt;h2&gt;Permissions&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Comme le port s&#233;rie est repr&#233;sent&#233; comme un fichier en &lt;i class=&quot;spip&quot;&gt;/dev&lt;/i&gt;, il sera n&#233;cessaire d'ex&#233;cuter le programme avec les droits de super-utilisateur root.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Sinon, il est possible de changer les droits d'acc&#232;s sur le fichier ou d'en changer le groupe. Voici quelques exemples sous Linux o&#249; le port s&#233;rie appara&#238;tra comme /dev/ttSx (/dev/cuaax sous FreeBSD).&lt;/p&gt; &lt;h3&gt;D&#233;finir l'acc&#232;s pour un nouveau groupe&lt;/h3&gt; &lt;p class=&quot;spip&quot;&gt;Cette solution est &#224; pr&#233;f&#233;rer.&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='3' class='spip_cadre' dir='ltr'&gt;$ groupadd robot $ chgrp robot /dev/ttyS0 $ chmod 0060 /dev/ttyS0&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt;
&lt;h3&gt;Donner acc&#232;s &#224; tous les utilisateurs possibles&lt;/h3&gt; &lt;p class=&quot;spip&quot;&gt;&#192; &#233;viter si possible, mais tol&#233;rable en phase de test.&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='1' class='spip_cadre' dir='ltr'&gt;$ chmod a+rw /dev/ttyS0&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt;
&lt;h3&gt;Donner l'acc&#232;s &#224; soit-m&#234;me seulement&lt;/h3&gt;
&lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='2' class='spip_cadre' dir='ltr'&gt;$ chown alice /dev/ttyS0 $ chmod 0600 /dev/ttyS0&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;Prenez note que si votre syst&#232;me est configur&#233; avec &lt;a href=&quot;http://en.wikipedia.org/wiki/Udev&quot; class=&quot;spip_out&quot;&gt;udev&lt;/a&gt;, ces commandes n'auront pas un effet permanent apr&#232;s red&#233;marrage. Il sera alors n&#233;cessaire d'adapter un fichier de configuration g&#233;n&#233;ralement situ&#233; dans le r&#233;pertoire &lt;strong class=&quot;spip&quot;&gt;/etc/udev/rules.d/&lt;/strong&gt;&lt;/p&gt; &lt;h2&gt;L'interface POSIX&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;&lt;strong class=&quot;spip&quot;&gt;&lt;code class='spip_code' dir='ltr'&gt;&amp;lt;termios.h&amp;gt;&lt;/code&gt;&lt;/strong&gt; fournit les structures de contr&#244;le ainsi que les fonctions POSIX qui permettront de d&#233;finir les propri&#233;t&#233;s des laisons s&#233;rielles qui seront mises en place.&lt;/p&gt; &lt;h3&gt;Vitesse de connection&lt;/h3&gt;
&lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='5' class='spip_cadre' dir='ltr'&gt;struct termios options; tcgetattr(srl_handle, &amp;options); cfsetospeed(&amp;options, B19200); options.c_cflag |= (CLOCAL | CREAD);&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;Dans ce bout de code, une structure &lt;strong class=&quot;spip&quot;&gt;termios&lt;/strong&gt; est d&#233;clar&#233;e et initialis&#233;e par la fonction &lt;strong class=&quot;spip&quot;&gt;tcgetattr&lt;/strong&gt;. Cette structure comprend plusieurs membres qui seront assign&#233;s &#224; des valeurs d&#233;finies par des &lt;i class=&quot;spip&quot;&gt;#define&lt;/i&gt; en utilisant des op&#233;rateurs bit &#224; bit.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Dans cet exemple, &lt;strong class=&quot;spip&quot;&gt;cfsetospeed&lt;/strong&gt; est utilis&#233; car cette fonction permet de d&#233;finir la vitesse (le &quot;&lt;i class=&quot;spip&quot;&gt;baud rate&lt;/i&gt;&quot;) dans le membre appropri&#233; de la structure termios. En effet, certains syst&#232;mes POSIX ne d&#233;finissent pas cette valeur des le m&#234;me membre (c_flag, c_ispeed, ou c_ospeed), d'o&#249; le besoin d'une fonction ind&#233;pendante du syst&#232;me.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Les options &lt;strong class=&quot;spip&quot;&gt;CLOCAL&lt;/strong&gt; et &lt;strong class=&quot;spip&quot;&gt;CREAD&lt;/strong&gt; sont d&#233;finies pour &#233;viter que le programme soit consid&#233;r&#233; en tant que propri&#233;taire du port. Pr&#233;cisons au passage que l'acc&#232;s aux membres de la structure devra toujours s'effectuer avec les op&#233;rateurs bit &#224; bit tel que montr&#233; ci-haut. Un OU binaire sert ici &#224; combiner les nouvelles options &#224; celles d&#233;j&#224; existantes dans le membre sans les &#233;craser.&lt;/p&gt; &lt;h3&gt;Bits de donn&#233;es (taille du charact&#232;re)&lt;/h3&gt;
&lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='2' class='spip_cadre' dir='ltr'&gt;options.c_cflag &amp;= ~CSIZE; options.c_cflag |= CS8;&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;Cette premi&#232;re ligne permet de mettre toute valeur pour cette option &#224; 0. CSIZE n'est donc ici qu'un masque &quot;&lt;i class=&quot;spip&quot;&gt;ni&#233;&lt;/i&gt;&quot; par &quot;&lt;code class='spip_code' dir='ltr'&gt;~&lt;/code&gt;&quot; et affect&#233; &#224; c_cflag par l'op&#233;rateur binaire &quot;&amp;&quot; (ET). CS8 (8 bits) peut ensuite &#234;tre attribu&#233; au membre par un OU binaire qui renverra n&#233;cessairement CS8 puisque les bits du masque sont maintenant tous &#224; 0. Rappelons-nous que le fonctionnement du OU peut se r&#233;sumer &#224; : &quot;l'un, ou l'autre, ou les deux en m&#234;me temps&quot;. Dans ce cas, &quot;l'un&quot; suffit &#224; faire &#233;galer le r&#233;sultat &#224; la valeur exacte de CS8.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Notez que CS5, CS6 et CS7 sont aussi disponibles.&lt;/p&gt; &lt;h3&gt;Parit&#233;&lt;/h3&gt; &lt;p class=&quot;spip&quot;&gt;Si on ne choisit pas de m&#233;thode de v&#233;rification par parit&#233; pour les donn&#233;es envoy&#233;es, c_flag devra &#234;tre d&#233;fini ainsi :&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='4' class='spip_cadre' dir='ltr'&gt;options.c_cflag &amp;= ~PARENB; options.c_cflag &amp;= ~CSTOPB; options.c_cflag &amp;= ~CSIZE; options.c_cflag |= CS8;&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;Avec CSIZE et CSTOPB, on reconna&#238;t ici la configuration 8N1 : 8 bits de donn&#233;es (&lt;strong class=&quot;spip&quot;&gt;8&lt;/strong&gt;), pas de parit&#233; (&lt;strong class=&quot;spip&quot;&gt;N&lt;/strong&gt;) et 1 bit d'arr&#234;t (&lt;strong class=&quot;spip&quot;&gt;1&lt;/strong&gt;),&lt;/p&gt; &lt;h3&gt;Application des attributs&lt;/h3&gt; &lt;p class=&quot;spip&quot;&gt;Apr&#232;s avoir d&#233;fini la structure termios avec les options voulues, elles doivent &#234;tre appliqu&#233;es par la fonction &lt;strong class=&quot;spip&quot;&gt;tcsetattr&lt;/strong&gt;.&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='1' class='spip_cadre' dir='ltr'&gt;tcsetattr(srl_handle, TCSANOW, &amp;options);&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;&lt;strong class=&quot;spip&quot;&gt;TCSANOW&lt;/strong&gt; indique que les changements doivent &#234;tre appliqu&#233;s imm&#233;diatement sans attendre la fin des donn&#233;es en entr&#233;e ou en sortie.&lt;/p&gt; &lt;h2&gt;Envoi des donn&#233;es&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Cette op&#233;ration s'effectuera avec le simple appel de la fonction &lt;strong class=&quot;spip&quot;&gt;write&lt;/strong&gt;.&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='1' class='spip_cadre' dir='ltr'&gt;if (write(srl_handle, &quot;g&quot;, 1) &amp;lt; 0){perror(&quot;write:&quot;);}&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;Le troisi&#232;me argument de la fonction indique le nombre d'octets &#224; &#233;crire. Lorsque les donn&#233;es ont pu &#234;tre envoy&#233;es, le nombre d'octets &#233;crits est retourn&#233;.&lt;/p&gt; &lt;h2&gt;Lecture&lt;/h2&gt;
&lt;h3&gt;Mode non bloquant&lt;/h3&gt; &lt;p class=&quot;spip&quot;&gt;Comme sp&#233;cifi&#233; plus haut, la fonction read() qui permet de lire les donn&#233;es sur le port s&#233;rie peut &#234;tre configur&#233;e en mode bloquant ou non. En effet par un appel &#224; fcntl() avec l'option &lt;strong class=&quot;spip&quot;&gt;FNDELAY&lt;/strong&gt;, read() retournera imm&#233;diatement avec la valeur 0 si aucune donn&#233;e n'est actuellement disponible.&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='1' class='spip_cadre' dir='ltr'&gt;fcntl(srl_handle, F_SETFL, FNDELAY);&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;La syntaxe de la fonction read est quant &#224; elle identique &#224; write :&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='1' class='spip_cadre' dir='ltr'&gt;if(read(srl_handle, buffer, 4) &amp;lt; 0){perror(&quot;read&quot;);}&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;O&#249; &lt;i class=&quot;spip&quot;&gt;buffer&lt;/i&gt; est un pointeur sur le tableau qui contiendra les donn&#233;es et &quot;4&quot; , dans cet exemple, le nombre d'octets &#224; copier dans cet espace.
&lt;/cadre&gt;&lt;/p&gt; &lt;h3&gt;select&lt;/h3&gt; &lt;p class=&quot;spip&quot;&gt;Dans bien des cas, des contraintes de temps de r&#233;ponse sont exig&#233;es dans un programme. En effet, plusieurs t&#226;ches doivent souvent &#234;tre ex&#233;cut&#233;es simultan&#233;ment. Un appel &#224; la fonction read peut ainsi compliquer quelque peu l'organisation du programme puisque deux choix pourraient s'offrir &#224; priori : attendre les donn&#233;es (mode bloquant), ou faire un &lt;i class=&quot;spip&quot;&gt;pooling&lt;/i&gt; sur read. La fonction &lt;strong class=&quot;spip&quot;&gt;select&lt;/strong&gt; peut alors s'av&#233;rer utile pour surveiller l'&#233;tat de plusieurs descripteurs de fichiers en m&#234;me temps. On pourrait par exemple d&#233;finir un ensemble &lt;i class=&quot;spip&quot;&gt;socket&lt;/i&gt; et &lt;i class=&quot;spip&quot;&gt;port s&#233;rie&lt;/i&gt; et &#224; l'arriv&#233;e de donn&#233;e sur l'un ou l'autre des descripteurs, &lt;i class=&quot;spip&quot;&gt;select&lt;/i&gt; renverrait une valeur sup&#233;rieure &#224; 0. On s'&#233;vite ainsi un &lt;i class=&quot;spip&quot;&gt;pooling&lt;/i&gt; syst&#233;matique pour chaque fichier &#224; surveiller. [&lt;a href=&quot;http://aqra.ca/#nb2-1&quot; name=&quot;nh2-1&quot; id=&quot;nh2-1&quot; class=&quot;spip_note&quot; title='[1] Un exemple de select : Using the SELECT System Call.' &gt;1&lt;/a&gt;]&lt;/p&gt; &lt;h3&gt;signal&lt;/h3&gt; &lt;p class=&quot;spip&quot;&gt;La programmation d'une routine de communication sur le port s&#233;rie pour un microcontr&#244;leur aurait &#233;t&#233; facilement r&#233;alis&#233;e par un m&#233;canisme d'interruptions. Toutefois, les interruptions mat&#233;rielles &#224; proprement dit ne sont pas accessibles dans l'espace utilisateur du syst&#232;me. Seul un pseudo-m&#233;canisme d'interruptions seraient alors envisageable par la programmation d'un &lt;i class=&quot;spip&quot;&gt;driver&lt;/i&gt; qui enverrait un signal &#224; un programme de l'espace d'utilisateur. [&lt;a href=&quot;http://aqra.ca/#nb2-2&quot; name=&quot;nh2-2&quot; id=&quot;nh2-2&quot; class=&quot;spip_note&quot; title='[2] Voir opening bananas with steamrollers.' &gt;2&lt;/a&gt;]&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Aussi, l'utilisation d'une extension temps r&#233;elle au noyau permettrait de r&#233;aliser de telles op&#233;rations avec des fonctions de son API. Ceci ne sera cependant pas couvert ici. [&lt;a href=&quot;http://aqra.ca/#nb2-3&quot; name=&quot;nh2-3&quot; id=&quot;nh2-3&quot; class=&quot;spip_note&quot; title='[3] Voir RTAI Serial Port Communication Example pour plus de (...)' &gt;3&lt;/a&gt;]&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Enfin, c'est l'option &lt;strong class=&quot;spip&quot;&gt;O_ASYNC&lt;/strong&gt; [&lt;a href=&quot;http://aqra.ca/#nb2-4&quot; name=&quot;nh2-4&quot; id=&quot;nh2-4&quot; class=&quot;spip_note&quot; title='[4] voir open(2).' &gt;4&lt;/a&gt;] pass&#233;e &#224; &lt;strong class=&quot;spip&quot;&gt;open&lt;/strong&gt; qui permettra la mise en place de ce m&#233;canisme. Un signal &lt;strong class=&quot;spip&quot;&gt;SIGIO&lt;/strong&gt; sera alors g&#233;n&#233;r&#233; &#224; toute arriv&#233;e ou &#233;criture de donn&#233;e (lorsque le buffer en sortie aura &#233;t&#233; rempli) pour un fichier ouvert en mode RW. Ensuite, il suffira de mettre en place une fonction de prise en charge du signal (&lt;i class=&quot;spip&quot;&gt;handler&lt;/i&gt;) attach&#233; &#224; ce signal et de bien s'assurer par &lt;i class=&quot;spip&quot;&gt;select&lt;/i&gt; que le &lt;i class=&quot;spip&quot;&gt;SIGIO&lt;/i&gt; re&#231;u corresponde bien &#224; l'&#233;v&#233;nement souhait&#233; sur le port. L'attribut &lt;strong class=&quot;spip&quot;&gt;F_SETOWN&lt;/strong&gt; [&lt;a href=&quot;http://aqra.ca/#nb2-5&quot; name=&quot;nh2-5&quot; id=&quot;nh2-5&quot; class=&quot;spip_note&quot; title='[5] Voir fcntl(2) .' &gt;5&lt;/a&gt;] devrait aussi &#234;tre appliqu&#233; avec la fonction &lt;strong class=&quot;spip&quot;&gt;fcntl&lt;/strong&gt; pour le descripteur de fichier du port s&#233;rie.&lt;/p&gt; &lt;h2&gt;R&#233;f&#233;rence&lt;/h2&gt;
&lt;div class='spip_document_612 spip_documents spip_documents_center' &gt;
&lt;a href=&quot;http://aqra.ca/IMG/jpg_display_thumbnail.php.jpg&quot; type=&quot;image/jpeg&quot; title='JPEG - 41.6 ko'&gt;&lt;img src='http://aqra.ca/IMG/cache-100x150/jpg_display_thumbnail.php-100x150-100x150.jpg' width='100' height='150' alt=&quot;JPEG - 41.6 ko&quot; /&gt;&lt;/a&gt;&lt;/div&gt; &lt;p class=&quot;spip&quot;&gt;Le livre &lt;a href=&quot;http://www.easysw.com/~mike/serial/&quot; class=&quot;spip_out&quot;&gt;Serial Programming Guide for POSIX Operating System de Michael R Sweet&lt;/a&gt; a servi de r&#233;f&#233;rence pour la r&#233;daction de cet article. Il est disponible librement sur internet ou peut &#234;tre achet&#233; via &lt;a href=&quot;http://www.lulu.com/content/146252&quot; class=&quot;spip_out&quot;&gt;lulu.com&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
		&lt;hr /&gt;
		&lt;div class='rss_notes'&gt;&lt;p class=&quot;spip_note&quot;&gt;[&lt;a href=&quot;http://aqra.ca/#nh2-1&quot; name=&quot;nb2-1&quot; class=&quot;spip_note&quot; title=&quot;info notes 2-1&quot;&gt;1&lt;/a&gt;] Un exemple de select : &lt;a href=&quot;http://www.easysw.com/~mike/serial/serial.html#5_2_2&quot; class=&quot;spip_out&quot;&gt;Using the SELECT System Call&lt;/a&gt;.&lt;/p&gt; &lt;p class=&quot;spip_note&quot;&gt;[&lt;a href=&quot;http://aqra.ca/#nh2-2&quot; name=&quot;nb2-2&quot; class=&quot;spip_note&quot; title=&quot;info notes 2-2&quot;&gt;2&lt;/a&gt;] Voir &lt;a href=&quot;http://kerneltrap.org/node/7580#comment-209433&quot; class=&quot;spip_out&quot;&gt;opening bananas with steamrollers&lt;/a&gt;.&lt;/p&gt; &lt;p class=&quot;spip_note&quot;&gt;[&lt;a href=&quot;http://aqra.ca/#nh2-3&quot; name=&quot;nb2-3&quot; class=&quot;spip_note&quot; title=&quot;info notes 2-3&quot;&gt;3&lt;/a&gt;] Voir &lt;a href=&quot;http://www.captain.at/rtai-serial-port-example.php&quot; class=&quot;spip_out&quot;&gt;RTAI Serial Port Communication Example&lt;/a&gt; pour plus de d&#233;tails.&lt;/p&gt; &lt;p class=&quot;spip_note&quot;&gt;[&lt;a href=&quot;http://aqra.ca/#nh2-4&quot; name=&quot;nb2-4&quot; class=&quot;spip_note&quot; title=&quot;info notes 2-4&quot;&gt;4&lt;/a&gt;] voir &lt;a href=&quot;http://www.die.net/doc/linux/man/man2/open.2.html&quot; class=&quot;spip_out&quot;&gt;open(2)&lt;/a&gt;.&lt;/p&gt; &lt;p class=&quot;spip_note&quot;&gt;[&lt;a href=&quot;http://aqra.ca/#nh2-5&quot; name=&quot;nb2-5&quot; class=&quot;spip_note&quot; title=&quot;info notes 2-5&quot;&gt;5&lt;/a&gt;] Voir &lt;a href=&quot;http://www.die.net/doc/linux/man/man2/fcntl.2.html&quot; class=&quot;spip_out&quot;&gt;fcntl(2) &lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
		
		</content:encoded>


		
		<enclosure url="http://aqra.ca/IMG/c_serialcom.c" length="2524" type="text/x-csrc" />
		

	</item>



	<item>
		<title>Repr&#233;sentation en m&#233;moire d'un triplet de canaux de couleur</title>
		<link>http://aqra.ca/Exprimer-un-triplet-de-couleur-sur</link>
		<guid isPermaLink="true">http://aqra.ca/Exprimer-un-triplet-de-couleur-sur</guid>
		<dc:date>2007-01-04T20:02:25Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Pierre-Luc Bacon</dc:creator>

<category domain="http://aqra.ca/-Programmation-">Programmation</category>


		<description>Tableau bidimensionnel d'entiers &lt;br /&gt;Sommaire &lt;br /&gt;Il peut parfois &#234;tre utile de disposer d'une image dans un tableau de telle sorte qu'on puisse retrouver la valeur d'un pixel directement par sa position. Un tableau du genre : &lt;div class=&quot;texteencadre-spip&quot;&gt;buffer[x][y]&lt;/div&gt;
&lt;br /&gt;J'ai &#233;t&#233; cependant confront&#233; au probl&#232;me suivant en voulant faire ainsi : comment exprimer ce triplet, en l'occurence trois char, dans un seul &#233;l&#233;ment du tableau ? La solution trouv&#233;e, peu &#233;l&#233;gante &#224; certains &#233;gards, est de disposer les trois canaux dans l'ordre RGB un &#224; (...)


-
&lt;a href="http://aqra.ca/-Programmation-" rel="directory"&gt;Programmation&lt;/a&gt;


		</description>


 <content:encoded>&lt;img src=&quot;http://aqra.ca/IMG/arton75.png&quot; alt=&quot;&quot; align=&quot;right&quot; width=&quot;128&quot; height=&quot;128&quot; class=&quot;spip_logos&quot; /&gt;
		&lt;div class='rss_texte'&gt;&lt;h2&gt;Tableau bidimensionnel d'entiers&lt;/h2&gt;
&lt;h2&gt;Sommaire&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Il peut parfois &#234;tre utile de disposer d'une image dans un tableau de telle sorte qu'on puisse retrouver la valeur d'un pixel directement par sa position. Un tableau du genre :&lt;/p&gt;
&lt;div class=&quot;texteencadre-spip&quot;&gt;buffer[x][y]&lt;/div&gt;
&lt;p class=&quot;spip&quot;&gt;J'ai &#233;t&#233; cependant confront&#233; au probl&#232;me suivant en voulant faire ainsi : comment exprimer ce triplet, en l'occurence trois &lt;i class=&quot;spip&quot;&gt;char&lt;/i&gt;, dans un seul &#233;l&#233;ment du tableau ? La solution trouv&#233;e, peu &#233;l&#233;gante &#224; certains &#233;gards, est de disposer les trois canaux dans l'ordre RGB un &#224; la suite de l'autre sur un &lt;i class=&quot;spip&quot;&gt;int&lt;/i&gt;. Puisque nous avons trois &lt;i class=&quot;spip&quot;&gt;char&lt;/i&gt;, qui occupent g&#233;n&#233;ralement 24bit (3*8bit), un &lt;i class=&quot;spip&quot;&gt;int&lt;/i&gt;, cod&#233; sur 32 bits, suffira &#224; les contenir.&lt;/p&gt; &lt;div class=&quot;texteencadre-spip&quot;&gt;
&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;int rgb;&lt;br /&gt; unsigned char r,g,b;&lt;/code&gt;&lt;/div&gt; &lt;/div&gt;
&lt;p class=&quot;spip&quot;&gt;Si on applique un op&#233;rateur de &lt;i class=&quot;spip&quot;&gt;cast&lt;/i&gt; sur un &lt;i class=&quot;spip&quot;&gt;char&lt;/i&gt; vers un &lt;i class=&quot;spip&quot;&gt;int&lt;/i&gt;, alors on aura de gauche &#224; droite 16 bits &#224; 0 et les 8 autres &#224; droite qui expriment la valeur contenue dans le &lt;i class=&quot;spip&quot;&gt;char&lt;/i&gt;. Ensuite on d&#233;place ces 8 bits qui nous int&#233;ressent vers la gauche de 16 bits avec un op&#233;rateur de &lt;i class=&quot;spip&quot;&gt;shift&lt;/i&gt; pour le canal R. Pour G, on applique la m&#234;me proc&#233;dure mais pour un d&#233;placement de 8 bits. Quant &#224; B, rien ne doit bouger. On a alors quelque chose semblable &#224; :&lt;/p&gt; &lt;div class=&quot;texteencadre-spip&quot;&gt;
&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;R=111111110000000000000000&lt;br /&gt; G=000000001111111100000000&lt;br /&gt; B=000000000000000011111111&lt;br /&gt;&lt;/code&gt;&lt;/div&gt; &lt;/div&gt;
&lt;p class=&quot;spip&quot;&gt;Avec cet encadr&#233; montrant une repr&#233;sentation o&#249; les trois canaux seraient &#224; 255, on voit qu'un OR des ces valeurs suffiraient &#224; les combiner dans l'ordre voulu.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;En des termes plus applicable &#224; un programme, on pourrait faire :&lt;/p&gt;
&lt;div class=&quot;texteencadre-spip&quot;&gt;rgb=(((int)r)&lt;&lt;16)|(((int)g)&lt;&lt;8)|((int)b) ;&lt;/div&gt;
&lt;p class=&quot;spip&quot;&gt;Une autre astuce pourrait consister &#224; d&#233;clarer un pointeur &lt;i class=&quot;spip&quot;&gt;unsigned char&lt;/i&gt; sur une variable &lt;i class=&quot;spip&quot;&gt;int 32 bits&lt;/i&gt;. Par la suite, on acc&#232;de &#224; la variable &lt;i class=&quot;spip&quot;&gt;int&lt;/i&gt; par le pointeur comme tableau :&lt;/p&gt;
&lt;div class=&quot;texteencadre-spip&quot;&gt;
&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;unsigned int pixel32;&lt;br /&gt; unsigned char *pixel = (unsigned char *)&amp;pixel32;&lt;br /&gt; &lt;br /&gt; pixel[0] = r;&lt;br /&gt; pixel[1] = g;&lt;br /&gt; pixel[2] = b&lt;br /&gt; pixel[3] = 0;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt; &lt;/div&gt;
&lt;p class=&quot;spip&quot;&gt;Maintenant pour retrouver les canaux individuels, on appliquera le masque appropri&#233; et effectuera le d&#233;calage requis pour avoir les 8 bits tous &#224; droite dans la repr&#233;sentation sur 32 bits. Ceci permettra ensuite de faire un &lt;i class=&quot;spip&quot;&gt;cast&lt;/i&gt; sur l'entier &lt;i class=&quot;spip&quot;&gt;int&lt;/i&gt; et d'obtenir la valeur souhait&#233;e dans la variable. Les masques utilis&#233;s dans ce &lt;i class=&quot;spip&quot;&gt;AND&lt;/i&gt; binaire sont trouv&#233;s du fait que l'op&#233;ration d'un bit &lt;i class=&quot;spip&quot;&gt;ET&lt;/i&gt; d'un autre &#224; 1 renvera n&#233;cessairement la m&#234;me valeur de base. De m&#234;me mani&#232;re, un &lt;i class=&quot;spip&quot;&gt;ET&lt;/i&gt; avec 0 aurait l'effet d'un &lt;i class=&quot;spip&quot;&gt;NON&lt;/i&gt;. Par exemple :&lt;/p&gt; &lt;div class=&quot;texteencadre-spip&quot;&gt;
&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt; 1011110101110111&lt;br /&gt; ET 0000000011111111&lt;br /&gt; -----------------&lt;br /&gt; 0000000001110111&lt;br /&gt;&lt;/code&gt;&lt;/div&gt; &lt;/div&gt;
&lt;p class=&quot;spip&quot;&gt;On pourrait donc coder quelque chose semblable &#224; :&lt;/p&gt; &lt;div class=&quot;texteencadre-spip&quot;&gt;
&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;r=(unsigned char) ((rgb &amp; 0xFF0000)&amp;gt;&amp;gt;16);&lt;br /&gt; g=(unsigned char) ((rgb &amp; 0xFF00)&amp;gt;&amp;gt;8);&lt;br /&gt; b=(unsigned char) (rgb &amp; 0xFF);&lt;br /&gt;&lt;/code&gt;&lt;/div&gt; &lt;/div&gt;
&lt;p class=&quot;spip&quot;&gt;Cette solution n'est peut-&#234;tre pas celle qui fait preuve du bon usage du langage C, mais devrait convenir dans la plupart des cas. De plus, elle a l'avantage de n'utiliser aucune fonctions sp&#233;ciales des biblioth&#232;ques. L'utilisation d'unions est aussi une possibilit&#233; plus lisibile &#224; consid&#233;rer pour effectuer une op&#233;ration similaire (merci &#224; Pierre pour cette suggestion).&lt;/p&gt; &lt;h2&gt;Tableau unidimensionnel de type unsigned char&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Lorsqu'on capture une image depuis une cam&#233;ra, celle-ci est accessible par un pointeur. Cette notion de pointeur &#233;tant li&#233;e &#224; celle de tableau, la zone m&#233;moire occup&#233;e par l'image sera assimilable &#224; un tableau unidimensionnel. En effet, soit un tableau &lt;i class=&quot;spip&quot;&gt;tbl[100]&lt;/i&gt;, alors &lt;i class=&quot;spip&quot;&gt;*tbl&lt;/i&gt; pointera sur le premier &#233;l&#233;ment en m&#233;moire de celui-ci. De cette mani&#232;re, si &lt;i class=&quot;spip&quot;&gt;*tbl&lt;/i&gt; correspond &#224; &lt;i class=&quot;spip&quot;&gt;tbl[0]&lt;/i&gt;, alors &lt;i class=&quot;spip&quot;&gt;*(tbl+1)&lt;/i&gt; sera &#233;quivalent &#224; &lt;i class=&quot;spip&quot;&gt;tbl[1]&lt;/i&gt;. Connaissant ceci, on peut donc calculer le &lt;i class=&quot;spip&quot;&gt;bond&lt;/i&gt; &#224; effetuer pour atteindre une case m&#233;moire donn&#233;e. Dans le cas de notre image, on peut en d&#233;duire les relations suivantes d'apr&#232;s l'illustration ci-dessous :&lt;/p&gt; &lt;div class=&quot;texteencadre-spip&quot;&gt;saut_r = 3*position_y*largeur + 3*position_x&lt;/div&gt;
&lt;div class=&quot;texteencadre-spip&quot;&gt;saut_g = 3*position_y*largeur + 3*position_x +1&lt;/div&gt;
&lt;div class=&quot;texteencadre-spip&quot;&gt;saut_b = 3*position_y*largeur + 3*position_x + 2&lt;/div&gt;
&lt;div class='spip_document_545 spip_documents spip_documents_center' &gt;
&lt;a href=&quot;http://aqra.ca/IMG/png_imgoffset.png&quot; type=&quot;image/png&quot; title='PNG - 4.8 ko'&gt;&lt;img src='http://aqra.ca/IMG/cache-150x87/png_imgoffset-150x87-150x87.png' width='150' height='87' alt=&quot;PNG - 4.8 ko&quot; /&gt;&lt;/a&gt;&lt;/div&gt; &lt;p class=&quot;spip&quot;&gt;Le trois (3) dans ces &#233;quations provient du nombre de canaux &#224; &lt;i class=&quot;spip&quot;&gt;sauter&lt;/i&gt; pour atteindre un emplacement donn&#233;.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Voici un bout de code montrant cette id&#233;e :&lt;/p&gt; &lt;div class=&quot;texteencadre-spip&quot;&gt;
&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;/*rgb(1;0)*/&lt;br /&gt; *(tbl+3)=55;&lt;br /&gt; *(tbl+4)=56;&lt;br /&gt; *(tbl+5)=57;&lt;br /&gt; &lt;br /&gt; r=*(tbl+(3*y*LARGEUR)+(3*x));&lt;br /&gt; g=*(tbl+(3*y*LARGEUR)+(3*x)+1);&lt;br /&gt; b=*(tbl+(3*y*LARGEUR)+(3*x)+2);&lt;br /&gt; &lt;br /&gt; printf(&quot;pos(%d;%d): rgb(%d;%d;%d)\n&quot;,x,y,r,g,b);&lt;br /&gt;&lt;/code&gt;&lt;/div&gt; &lt;/div&gt;
&lt;h2&gt;Utilisation d'une structure&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Voil&#224; maintenant un moyen plus lisible et plus direct de repr&#233;senter ce triplet dans un emplacement du tableau &#224; deux dimensions. On peut donc d&#233;clarer un type &lt;i class=&quot;spip&quot;&gt;triplet&lt;/i&gt; ainsi :&lt;/p&gt; &lt;div class=&quot;texteencadre-spip&quot;&gt;
&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;typedef struct {&lt;br /&gt; unsigned char r;&lt;br /&gt; unsigned char g;&lt;br /&gt; unsigned char b;&lt;br /&gt; } triplet;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt; &lt;/div&gt;
&lt;p class=&quot;spip&quot;&gt;Il suffit par la suite d'initialiser dynamiquement ou statiquement un tableau de type &lt;i class=&quot;spip&quot;&gt;triplet&lt;/i&gt;. On acc&#233;dera aux &#233;l&#233;ments du tableau ainsi :&lt;/p&gt; &lt;div class=&quot;texteencadre-spip&quot;&gt;
&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;triplet rgb[LARGEUR][HAUTEUR];&lt;br /&gt; rgb[x][y].r=200;&lt;br /&gt; rgb[x][y].g [...]&lt;br /&gt; rgb[x][y].b [...]&lt;br /&gt;&lt;/code&gt;&lt;/div&gt; &lt;/div&gt;
&lt;h2&gt;Utilisation d'une Union&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Un collaborateur (&lt;i class=&quot;spip&quot;&gt;user0081&lt;/i&gt;) propose une solution tout aussi &#233;l&#233;gante qui consiste &#224; utiliser une &lt;i class=&quot;spip&quot;&gt;union&lt;/i&gt;. Ceci permettra d'arriver au m&#234;me r&#233;sultat que ci-haut, sans la complexit&#233; des op&#233;rateurs binaires.&lt;/p&gt; &lt;div class=&quot;texteencadre-spip&quot;&gt;
&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;typedef union {&lt;br /&gt; int rgb;&lt;br /&gt; struct {&lt;br /&gt; unsigned char r;&lt;br /&gt; unsigned char g;&lt;br /&gt; unsigned char b;&lt;br /&gt; } chan;&lt;br /&gt; } pixel&lt;br /&gt;&lt;/code&gt;&lt;/div&gt; &lt;/div&gt;
&lt;p class=&quot;spip&quot;&gt;Pour un &#233;l&#233;ment donn&#233; d'un tableau &#224; deux dimensions qui contient tous les pixels de l'image, on pourra retrouver &#224; la fois chacun des canaux s&#233;par&#233;ment ainsi que leur combinaison sur un entier :&lt;/p&gt; &lt;div class=&quot;texteencadre-spip&quot;&gt;
&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;pixel image[LARGEUR][HAUTEUR];&lt;br /&gt; rgb=image[x][y].rgb;&lt;br /&gt; r=image[x][y].chan.r;&lt;br /&gt; g=image[x][y].chan.g;&lt;br /&gt; b=image[x][y].chan.b;&lt;/code&gt;&lt;/div&gt; &lt;/div&gt;
&lt;p class=&quot;spip&quot;&gt;L'exemple suivant illustre davantage l'astuce mise en jeu :&lt;/p&gt;
&lt;div class=&quot;texteencadre-spip&quot;&gt;
&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;typedef union {&lt;br /&gt; int yuv;&lt;br /&gt; struct {&lt;br /&gt; unsigned char y;&lt;br /&gt; unsigned char u;&lt;br /&gt; unsigned char v;&lt;br /&gt; } chan;&lt;br /&gt; } pixel;&lt;br /&gt; pixel image[240][240];&lt;br /&gt; &lt;br /&gt; image[0][2].chan.y=23;&lt;br /&gt; image[0][2].chan.u=128;&lt;br /&gt; image[0][2].chan.v=57;&lt;br /&gt; &lt;br /&gt; printf(&quot;YUV: %d:%d:%d\t YUV32:%d\n&quot;,image[0][2].chan.y,image[0][2].chan.u,image[0][2].chan.v,image[0][2].yuv);&lt;/code&gt;&lt;/div&gt; &lt;/div&gt;
&lt;p class=&quot;spip&quot;&gt;On obtiendra alors en sortie :&lt;/p&gt;
&lt;div class=&quot;texteencadre-spip&quot;&gt;
&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; YUV: 23:128:57 YUV32:3768343&lt;br /&gt; R,G,B: ff,c8,9b&lt;br /&gt;&lt;/code&gt;&lt;/div&gt; &lt;/div&gt;
&lt;p class=&quot;spip&quot;&gt;Soit 23-&gt;10111 en binaire, 128-&gt;10000000 et 57-&gt;111001, 3768343 correspond alors &#224; &lt;strong class=&quot;spip&quot;&gt;111001&lt;/strong&gt;10000000000&lt;strong class=&quot;spip&quot;&gt;10111&lt;/strong&gt;. Ce r&#233;sultat est alors de la m&#234;me forme que celui obtenu par l'approche &quot;binaire pure&quot; avec les canaux YUV (ou RGB) dans l'ordre voulu.&lt;/p&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>



	<item>
		<title>D&#233;terminer l'histogramme HSV d'une image RGB</title>
		<link>http://aqra.ca/Determiner-l-histogramme-HSV-d-une</link>
		<guid isPermaLink="true">http://aqra.ca/Determiner-l-histogramme-HSV-d-une</guid>
		<dc:date>2005-12-29T08:09:05Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Pierre-Luc Bacon</dc:creator>

<category domain="http://aqra.ca/-Programmation-">Programmation</category>

		<dc:subject>traitement image</dc:subject>
		<dc:subject>niveaux de gris</dc:subject>
		<dc:subject>ppm</dc:subject>

		<description>Il m'&#233;tait n&#233;cessaire r&#233;cemment d'&#233;tudier les histogrammes d'une s&#233;rie d'images enregistr&#233;es sous le format jpg. Or, je n'ai pu trouver d'outils satisfaisants &#224; cette tache sous Linux. J'ai donc choisi de coder la solution. &lt;br /&gt;Pour r&#233;duire la complexit&#233; du d&#233;veloppement qui &#233;tait contraint &#224; quelques heures, il a &#233;t&#233; convenu que le format PPM &#233;tait tout indiqu&#233; &#224; nouveau pour ce type d'exp&#233;rimentation. En effet, le programme nivgris, d&#233;taill&#233; dans cet [article-35], allait servir de base &#224; l'autre. &#201;galement, il (...)


-
&lt;a href="http://aqra.ca/-Programmation-" rel="directory"&gt;Programmation&lt;/a&gt;

/ 
&lt;a href="http://aqra.ca/+-traitement-image-+" rel="tag"&gt;traitement image&lt;/a&gt;, 
&lt;a href="http://aqra.ca/+-niveaux-de-gris-+" rel="tag"&gt;niveaux de gris&lt;/a&gt;, 
&lt;a href="http://aqra.ca/+-ppm-+" rel="tag"&gt;ppm&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_chapo'&gt;Il m'&#233;tait n&#233;cessaire r&#233;cemment d'&#233;tudier les histogrammes d'une s&#233;rie d'images enregistr&#233;es sous le format jpg. Or, je n'ai pu trouver d'outils satisfaisants &#224; cette tache sous Linux. J'ai donc choisi de coder la solution.&lt;/div&gt;
		&lt;div class='rss_texte'&gt;&lt;p class=&quot;spip&quot;&gt;Pour r&#233;duire la complexit&#233; du d&#233;veloppement qui &#233;tait contraint &#224; quelques heures, il a &#233;t&#233; convenu que le format PPM &#233;tait tout indiqu&#233; &#224; nouveau pour ce type d'exp&#233;rimentation. En effet, le programme &lt;i class=&quot;spip&quot;&gt;nivgris&lt;/i&gt;, d&#233;taill&#233; dans cet [article-35], allait servir de base &#224; l'autre. &#201;galement, il avait &#233;t&#233; d&#233;cid&#233; que Gnuplot allait servir &#224; l'affichage des donn&#233;es de l'histogramme : ce qui r&#233;duit consid&#233;rablement les demandes en travail par rapport &#224; une solution bas&#233;e par exemple sur la librairie GD. Cela permet donc, par l'entremise de la biblioth&#232;que &lt;i class=&quot;spip&quot;&gt;gnuplot_i&lt;/i&gt; qui n'est qu'une &quot;interface&quot;, d'obtenir directement un graphique en format png.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Le principe du programme se pr&#233;sente donc ainsi :&lt;/p&gt; &lt;ol class=&quot;spip&quot;&gt;&lt;li class=&quot;spip&quot;&gt; Ouvrir le fichier ppm&lt;/li&gt;&lt;li class=&quot;spip&quot;&gt; Scruter tous les pixels RGB et les convertir en HSV&lt;/li&gt;&lt;li class=&quot;spip&quot;&gt; Incr&#233;menter l'&#233;l&#233;ment d'un tableau - 3 en tout (H,S et V) - selon la valeur de H, S ou V qui sert d'indice&lt;/li&gt;&lt;li class=&quot;spip&quot;&gt; Produire un fichier dat pour gnuplot&lt;/li&gt;&lt;li class=&quot;spip&quot;&gt; Fermer le fichier&lt;/li&gt;&lt;li class=&quot;spip&quot;&gt; Cr&#233;er les graphiques avec gnuplot_i&lt;/li&gt;&lt;/ol&gt;
&lt;h2&gt;Conversion HSV vers RGB&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Le format HSV, acronyme de &quot;Hue Saturation Value&quot;, est un format qui poss&#232;de des caract&#233;ristiques int&#233;ressantes pour toute application d'analyse vid&#233;o. En effet, contrairement au RGB, le HSV est un format dit &quot;naturel&quot; car sa d&#233;finition rel&#232;ve davantage de la conception humaine de la couleur plut&#244;t que celle du RGB qui s'applique d'abord &#224; des dispositifs &#233;lectroniques. Cela rend donc le HSV apte par exemple &#224; une op&#233;ration de seuillage des couleurs qui autrement pourrait &#234;tre facilement fauss&#233;e quelque facteur externe.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;La signification des composants du HSV peuvent s'expliquer de cette mani&#232;re :&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt; Le hue peut &#234;tre d&#233;finie comme le &quot;type&quot; de couleur ou la &quot;teinte&quot;. Ex : bleu, rouge, orange
&lt;br /&gt; La saturation est la &quot;puret&#233;&quot; d'une couleur. Plus sa valeur approche de 0, plus la couleur devient gris&#226;tre.
&lt;br /&gt; V (value) est la claret&#233; de la couleur.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Chacune de ces valeurs est d&#233;finie dans une gamme d&#233;termin&#233;e. Par exemple, le hue variera g&#233;n&#233;ralement de 0 &#224; 360 mais peut &#234;tre parfois normalis&#233; entre 0 et 100. Quant &#224; S et V, ceux-ci varient de 0 &#224; 1 ou, exprim&#233; en pourcentage, de 0 &#224; 100%. Il est plus facile de comprendre ceci en observant cette repr&#233;sentation du HSV :&lt;/p&gt; &lt;div class='spip_document_481 spip_documents spip_documents_center' &gt;
&lt;a href=&quot;http://aqra.ca/IMG/jpg/HSV_cone.jpg&quot; type=&quot;image/jpeg&quot; title='JPEG - 32.1 ko'&gt;&lt;img src='http://aqra.ca/IMG/jpg/HSV_cone.jpg' width='520' height='390' alt=&quot;JPEG - 32.1 ko&quot; /&gt;&lt;/a&gt;
&lt;div class='spip_doc_titre' style='width:350px;'&gt;&lt;strong&gt;Repr&#233;sentation du HSV par un c&#244;ne&lt;/strong&gt;&lt;/div&gt;&lt;/div&gt; &lt;p class=&quot;spip&quot;&gt;Le hue est donc vu comme la variation autour de la circonf&#233;rence du c&#244;ne, d'o&#249; s'explique sa gamme de valeurs comprises entre 0 et 360 degr&#233;s. La saturation s'explique comme le rayon d'un disque du c&#244;ne. V varie finalement du sommet du c&#244;ne &#224; sa base.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Outre la m&#233;thode th&#233;orique directement issue du mod&#232;le math&#233;matique, la conversion d'une valeur en RGB vers le HSI peut &#234;tre effectu&#233;e sans trop de charge du processeur. En effet, il se trouve que l'on puisse recourir &#224; ce raccourci :&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='7' class='spip_cadre' dir='ltr'&gt;H = 60*(g-b)/(max(r,g,b)-min(r-g-b)) si max(r,g,b) = r = 60*(b-r)/(max(r,g,b)-min(r,g,b)) si max(r,g,b) = g = 60*(r-g)/(max(r,g,b)-min(r,g,b)) si max(r,g,b) = b S = (max(r,g,b) - min(r,g,b)) / max(r,g,b) V = max(r,g,b)&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;&#201;galement deux exceptions se pr&#233;sentent :&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt; &lt;i class=&quot;spip&quot;&gt;Si max=min alors h ne peut &#234;tre d&#233;finit&lt;/i&gt;
&lt;br /&gt; &lt;i class=&quot;spip&quot;&gt;Si max=0 alors s ne peut &#234;tre d&#233;finit&lt;/i&gt;&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Cette conversion peut-&#234;tre cod&#233;e ainsi dans une fonction :&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='26' class='spip_cadre' dir='ltr'&gt;void rgbHsv(int r, int g, int b, int *h, int *s, int *v) { int min,max; min=MIN(r,g,b); max=MAX(r,g,b); *v=ROUND(((float) (max)/256)*100); if(max != 0) *s=ROUND(((float) (max - min)/max)*100); else {*h=0;*s=0;*v=0;return;} if(max == min) {*h=0;return;} if(max == r) *h=ROUND(((float)(g-b)/(max-min))*60); else if(max == g) *h=ROUND((((float)(b-r)/(max-min))+2)*60); else *h=ROUND((((float)(r-g)/(max-min))+4)*60); if(*h&amp;lt;0) *h+=360; }&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;Cette fonction, appell&#233;e avec la valeur des composants RGB en param&#232;tre ainsi que l'adresse sur les variables pour H,S et V, retournera H dans l'intervalle 0-360 ainsi que S et V dans 0-100.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Notez ici que les fonction max et min sont en fait des macros qu'il faudra prendre soin de d&#233;finir dans l'ent&#234;te :&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='3' class='spip_cadre' dir='ltr'&gt;#define MAX(x,y,z) (x&amp;gt;y?x:y)&amp;gt;z?(x&amp;gt;y?x:y):z #define MIN(x,y,z) (x&amp;lt;y?x:y)&amp;lt;z?(x&amp;lt;y?x:y):z #define ROUND(v) (v&amp;gt;=0?(int)((v)+0.5):(int)((v)-0.5))&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt;
&lt;h2&gt;Cr&#233;ation de l'histogramme&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Comme expliqu&#233; sommairement plus-haut, le principe de calcul de l'histogramme se base sur l'incr&#233;mentation d'un tableau pour H, S et V. Ceci est visible dans cette partie du programme :&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='13' class='spip_cadre' dir='ltr'&gt;for (y = 0; y &amp;lt; hauteur; y++) { for (x = 0; x &amp;lt; largeur; x++) { r = fgetc (fpr); g = fgetc (fpr); b = fgetc (fpr); rgbHsv(r,g,b,&amp;h,&amp;s,&amp;v); ++hue[h]; ++sat[s]; ++val[v]; } }&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;Le fichier PPM est parcouru pour obtenir toutes les valeurs RGB des pixels et &#234;tre convertis en HSV. Par la suite, on incr&#233;mente un &#233;l&#233;ment d'un des tableaux &#224; la position index&#233;e par la valeur convertie. Par exemple, si l'on trouve que la valeur de hue pour un pixel vaut 134, alors hue[134] sera incr&#233;ment&#233;. De cette mani&#232;re, chaque &#233;l&#233;ment du tableau repr&#233;sente chacune des valeurs enti&#232;res possibles pour H,S et V.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Par la suite, on proc&#232;de &#224; l'op&#233;ration contraire de lecture du tableau pour &#233;crire un fichier .dat pour Gnuplot :&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='8' class='spip_cadre' dir='ltr'&gt;/*Ecriture du fichier dat*/ for(x=0;x&amp;lt;361;x++) { if(x&amp;lt;101) fprintf(fpw,&quot;%d %d %d %d\n&quot;,x,hue[x],sat[x],val[x]); else fprintf(fpw,&quot;%d %d\n&quot;,x,hue[x]); }&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt; &lt;p class=&quot;spip&quot;&gt;Finalement, apr&#232;s avoir &quot;d&#233;roul&#233;&quot; les tableaux dans le m&#234;me fichier Gnuplot et ferm&#233; ce dernier, on peut cr&#233;er les fichier png &#224; partir de gnuplot_i. Consultez le manuel de r&#233;f&#233;rence de Gnuplot et gnuplot_i pour en savoir davantage.&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='28' class='spip_cadre' dir='ltr'&gt;/*Creation du fichier png*/ gnuplot_ctrl * h1; gnuplot_ctrl * h2; h1 = gnuplot_init() ; gnuplot_cmd(h1, &quot;set title \&quot;Histogramme de s et v pour %s\&quot;&quot;,argv[1]); gnuplot_cmd(h1, &quot;set terminal png&quot;); gnuplot_cmd(h1, &quot;set output \&quot;sv.png\&quot;&quot;); gnuplot_cmd(h1, &quot;set mxtics 4&quot;); gnuplot_cmd(h1, &quot;set mytics 4&quot;); gnuplot_cmd(h1, &quot;set xtics 10&quot;); gnuplot_setstyle(h1,&quot;boxes&quot;); gnuplot_set_xlabel(h1,&quot;&quot;); gnuplot_set_ylabel(h1,&quot;px&quot;); gnuplot_cmd(h1, &quot;plot '%s' using 1:3 with boxes title \&quot;saturation\&quot;, '%s' using 1:4 with boxes title \&quot;value\&quot;&quot;, argv[2],argv[2]) ; h2 = gnuplot_init() ; gnuplot_cmd(h2, &quot;set title \&quot;Histogramme du hue pour %s\&quot;&quot;,argv[1]); gnuplot_cmd(h2, &quot;set terminal png&quot;); gnuplot_cmd(h2, &quot;set output \&quot;hue.png\&quot;&quot;); gnuplot_cmd(h2, &quot;set mxtics 4&quot;); gnuplot_cmd(h2, &quot;set mytics 4&quot;); gnuplot_set_xlabel(h2,&quot;hue&quot;); gnuplot_set_ylabel(h2,&quot;px&quot;); gnuplot_cmd(h2, &quot;plot '%s' using 1:2 with boxes title \&quot;hue\&quot;&quot;,argv[2]) ; gnuplot_close(h1) ; gnuplot_close(h2) ;&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt;
&lt;h2&gt;R&#233;sultat&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Apr&#232;s avoir ex&#233;cut&#233; hsvhist sur une image ppm de cette mani&#232;re :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;code class='spip_code' dir='ltr'&gt;hsvhist fichier.ppm donnees&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;3 fichiers sont cr&#233;&#233;s. D'abord le fichier gnuplot qui contient les histogrammes pour H,S et V ainsi que les graphiques en format png du hue et de sv.&lt;/p&gt; &lt;div class='spip_document_485 spip_documents spip_documents_center' &gt;
&lt;a href=&quot;http://aqra.ca/IMG/jpg/echantillon_c7.jpg&quot; type=&quot;image/jpeg&quot; title='JPEG - 10.4 ko'&gt;&lt;img src='http://aqra.ca/IMG/cache-282x376/echantillon_c7-282x376.jpg' width='282' height='376' alt=&quot;JPEG - 10.4 ko&quot; /&gt;&lt;/a&gt;
&lt;div class='spip_doc_titre' style='width:282px;'&gt;&lt;strong&gt;Image &#224; analyser&lt;/strong&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class='spip_document_484 spip_documents spip_documents_center' &gt;
&lt;a href=&quot;http://aqra.ca/IMG/png/sv.png&quot; type=&quot;image/png&quot; title='PNG - 4.2 ko'&gt;&lt;img src='http://aqra.ca/IMG/cache-520x390/sv-520x390.png' width='520' height='390' alt=&quot;PNG - 4.2 ko&quot; /&gt;&lt;/a&gt;
&lt;div class='spip_doc_titre' style='width:350px;'&gt;&lt;strong&gt;Saturation et Value&lt;/strong&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class='spip_document_483 spip_documents spip_documents_center' &gt;
&lt;a href=&quot;http://aqra.ca/IMG/png/hue.png&quot; type=&quot;image/png&quot; title='PNG - 4.4 ko'&gt;&lt;img src='http://aqra.ca/IMG/cache-520x390/hue-520x390.png' width='520' height='390' alt=&quot;PNG - 4.4 ko&quot; /&gt;&lt;/a&gt;
&lt;div class='spip_doc_titre' style='width:350px;'&gt;&lt;strong&gt;Histogramme du hue&lt;/strong&gt;&lt;/div&gt;&lt;/div&gt; &lt;p class=&quot;spip&quot;&gt;Les r&#233;sultats semblent concluants et l'outil, bien pratique. &#201;galement, il serait possible de faire &#233;voluer le programme de telle sorte qu'il puisse cr&#233;er d'autres graphiques plus d&#233;taill&#233;s par exemple. Cependant, dans le cadre des exigences initiales, l'objectif est atteint. L'&#233;tude de ces histogrammes est donc maintenant &#224; venir&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Notez d'ailleurs cette caract&#233;ristique du hue pour la couleur de &quot;peau&quot; pr&#232;s de 25...&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;&lt;strong class=&quot;spip&quot;&gt;&#192; consulter &#233;galement...&lt;/strong&gt;&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;&lt;a href=&quot;http://aqra.ca/Dimensionnement-et-conception-d&quot; class=&quot;spip_in&quot;&gt;Conversion en bloc JPG vers PPM&lt;/a&gt;&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;&lt;a href=&quot;http://aqra.ca/Conversion-d-images-couleur-en&quot; class=&quot;spip_in&quot;&gt;Conversion d'images couleur en niveaux de gris&lt;/a&gt;&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;&lt;a href=&quot;http://ndevilla.free.fr/gnuplot/gnuplot_i/index.html&quot; class=&quot;spip_out&quot;&gt;gnuplot_i&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;
		
		</content:encoded>


		
		<enclosure url="http://aqra.ca/IMG/gz/hsvhist-1.1.tar.gz" length="17014" type="application/x-gzip" />
		

	</item>



	<item>
		<title>Programmation de r&#233;seaux neuronaux artificiels sous Linux</title>
		<link>http://aqra.ca/Programmation-de-reseaux-neuronaux</link>
		<guid isPermaLink="true">http://aqra.ca/Programmation-de-reseaux-neuronaux</guid>
		<dc:date>2005-12-27T06:01:12Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Pierre-Luc Bacon</dc:creator>

<category domain="http://aqra.ca/-Programmation-">Programmation</category>


		<description>&#201;tant contraint par des &#233;ch&#233;ances trop demandantes, mon projet de d&#233;veloppement d'une biblioth&#232;que de fonctions pour l'impl&#233;mentation d'un algorithme de r&#233;tropropagation de l'erreur (BPNN) a &#233;t&#233; interrompu par la d&#233;couverte d'un outil puissant qui sera applicable dans les d&#233;lais. &lt;br /&gt;Bien que la compr&#233;hension g&#233;n&#233;rale des principes soutenant les mod&#232;les de r&#233;seaux neuronaux puisse &#234;tre assez accessible, il en est cependant tout autrement quand vient le temps d'impl&#233;menter ces concepts dans un programme. Plut&#244;t (...)


-
&lt;a href="http://aqra.ca/-Programmation-" rel="directory"&gt;Programmation&lt;/a&gt;


		</description>


 <content:encoded>&lt;img src=&quot;http://aqra.ca/IMG/arton60.gif&quot; alt=&quot;&quot; align=&quot;right&quot; width=&quot;150&quot; height=&quot;150&quot; class=&quot;spip_logos&quot; /&gt;
		&lt;div class='rss_chapo'&gt;&#201;tant contraint par des &#233;ch&#233;ances trop demandantes, mon projet de d&#233;veloppement d'une biblioth&#232;que de fonctions pour l'impl&#233;mentation d'un algorithme de r&#233;tropropagation de l'erreur (BPNN) a &#233;t&#233; interrompu par la d&#233;couverte d'un outil puissant qui sera applicable dans les d&#233;lais.&lt;/div&gt;
		&lt;div class='rss_texte'&gt;&lt;p class=&quot;spip&quot;&gt;Bien que la compr&#233;hension g&#233;n&#233;rale des principes soutenant les mod&#232;les de r&#233;seaux neuronaux puisse &#234;tre assez accessible, il en est cependant tout autrement quand vient le temps d'impl&#233;menter ces concepts dans un programme. Plut&#244;t que de coder enti&#232;rement des biblioth&#232;ques d&#233;di&#233;es &#224; cette fin, il serait nettement plus efficace de tirer profit des travaux d&#233;j&#224; r&#233;alis&#233;s dans le domaine. Ainsi, la biblioth&#232;que FANN, acronyme de &lt;i class=&quot;spip&quot;&gt;Fast Artificial Neural Network Library&lt;/i&gt;, nous permet de parvenir &#224; notre objectif rapidement.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;FANN permet le d&#233;ploiement d'algorithmes de r&#233;seaux neuronaux artificiels multicouches &#224; r&#233;tropropagation de l'erreur (&lt;i class=&quot;spip&quot;&gt;backpropagation neural network&lt;/i&gt;) avec acc&#232;s &#224; tous ses param&#232;tres : pas d'apprentissage, nombre d'&#233;poques etc. &#201;galement, l'acc&#232;s aux fonctions peut se faire &#224; partir de plusieurs langages (C++, PHP, Rubby, Python, Pure Data, .NET et Delphi pour nommer que ceux-l&#224;) autant sous Linux que Windows.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Fait &#224; ne pas n&#233;gliger : il est possible d'ajuster les param&#232;tres du r&#233;seaux de mani&#232;re &#224; l'optimiser au fil de l'apprentissage. Par exemple, cette fonctionalit&#233; s'av&#233;rerait particuli&#232;rement int&#233;ressante dans le cas d'un syst&#232;me dynamique d'&#233;vitement des minimas locaux.&lt;/p&gt; &lt;h2&gt;Installation&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;L'installation &#224; partir des sources se fait de mani&#232;re classique. Il faut d'abord r&#233;cup&#233;rer l'archive sur ce site :&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;&lt;a href=&quot;http://leenissen.dk/fann/&quot; class=&quot;spip_url spip_out&quot;&gt;http://leenissen.dk/fann/&lt;/a&gt;&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;D&#233;compresser l'archive :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;tar xjf fann-1.x.x.tar.bz2&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;ou&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;tar xzf fann-1.x.x.tar.gz&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Ensuite dans le r&#233;pertoire :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;./configure &#8212;prefix=/usr &lt;br&gt;make&lt;br&gt;su -c &quot;make install&quot;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;La compilation ne devrait pas poser de probl&#232;mes particuliers. Si tel est le cas, assurez-vous qu'il ne manque pas de biblioth&#232;ques essentielles, ce qui serait fort surprenant compte tenu des demandes minimales de FANN.&lt;/p&gt; &lt;h2&gt;Exemple&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Le but de cet article n'&#233;tant pas de reproduire tout le d&#233;tail du manuel de r&#233;f&#233;rence du projet FANN, je n'&#233;laborerai davantage sur ses fonctions. Le code pr&#233;sent&#233; plus bas sera divis&#233; en deux programmes : l'un permettant d'entra&#238;ner le r&#233;seau &#224; partir de donn&#233;es, et l'autre d'ex&#233;cuter le r&#233;seau une fois correctement ajust&#233;.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;&lt;strong class=&quot;spip&quot;&gt;Entra&#238;nement&lt;/strong&gt;&lt;br&gt;&lt;/p&gt; &lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; include &quot;fann.h&quot;&lt;br /&gt; &lt;br /&gt; int main()&lt;br /&gt; {&lt;br /&gt; const float connection_rate = 1;&lt;br /&gt; const float learning_rate = 0.5;&lt;br /&gt; const unsigned int num_input = 2;&lt;br /&gt; const unsigned int num_output = 1;&lt;br /&gt; const unsigned int num_layers = 3;&lt;br /&gt; const unsigned int num_neurons_hidden = 4;&lt;br /&gt; const float desired_error = 0.0001;&lt;br /&gt; const unsigned int max_iterations = 500000;&lt;br /&gt; const unsigned int iterations_between_reports = 1000;&lt;br /&gt; &lt;br /&gt; struct fann *ann = fann_create(connection_rate, learning_rate, num_layers,&lt;br /&gt; num_input, num_neurons_hidden, num_output);&lt;br /&gt; &lt;br /&gt; fann_train_on_file(ann, &quot;xor.data&quot;, max_iterations,&lt;br /&gt; iterations_between_reports, desired_error);&lt;br /&gt; &lt;br /&gt; fann_save(ann, &quot;xor_float.net&quot;);&lt;br /&gt; &lt;br /&gt; fann_destroy(ann);&lt;br /&gt; &lt;br /&gt; return 0;&lt;br /&gt; }&lt;br /&gt;&lt;/code&gt;&lt;/div&gt; &lt;p class=&quot;spip&quot;&gt;Notez ici que cette premi&#232;re partie provient directement du manuel de FANN et nous servira dans le cas pr&#233;sent &#224; v&#233;rifier d'abord si nous parvenons &#224; compiler un programme avec la biblioth&#232;que et ensuite &#224; introduire les concepts de l'API.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;La compilation peut se faire ainsi :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;gcc entrainement.c -o entrainement -lfann -lm -O3&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;S'il arrivait que vous obteniez un message d'erreur tel que :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;ld : can't locate file for -lfann &lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Cela peut signifier que vous ayez install&#233; FANN dans un r&#233;pertoire non reconnu par ld (dans /usr/local/lib/ par exemple). Dans ce cas, on peut proc&#233;der en d&#233;finissant une variable d'environnement qui sp&#233;cifie le r&#233;pertoire &#224; utiliser :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;export LD_LIBRARY_PATH=/usr/local/lib/&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Les &#233;tapes permettant de parvenir &#224; un r&#233;sultat sont r&#233;duites. Ainsi, suffit-il d'abord de cr&#233;er un r&#233;seau en renseignant un pointeur de structure fann avec la fonction fann_create().&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;code class='spip_code' dir='ltr'&gt;struct fann * fann_create(float connection_rate, float learning_rate, unsigned int num_layers, unsigned int ...);&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;L'argument &lt;i class=&quot;spip&quot;&gt;connection_rate&lt;/i&gt; permet d'indiquer si le r&#233;seau sera compl&#232;tement connect&#233; avec comme valeur 1 pour une structure d'interconnection compl&#232;te et 0.2 pour une autre &#224; 20% par exemple.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Ensuite est charg&#233; un fichier contenant les donn&#233;es qui formeront le corpus d'apprentissage. Celui-ci respecte la syntaxe suivante :
&lt;br&gt;&lt;/p&gt; &lt;div class='spip_document_480 spip_documents spip_documents_center' &gt;
&lt;a href=&quot;http://aqra.ca/IMG/jpg/ann.jpg&quot; type=&quot;image/jpeg&quot; title='JPEG - 20.6 ko'&gt;&lt;img src='http://aqra.ca/IMG/cache-412x240/ann-412x240.jpg' width='412' height='240' alt=&quot;JPEG - 20.6 ko&quot; /&gt;&lt;/a&gt;
&lt;div class='spip_doc_titre' style='width:350px;'&gt;&lt;strong&gt;Syntaxe d'un fichier de donn&#233;es pour la r&#232;gle XOR&lt;/strong&gt;&lt;/div&gt;&lt;/div&gt; &lt;p class=&quot;spip&quot;&gt;La fonction fann_train_on_file permet d'effectuer cette op&#233;ration :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; void fann_train_on_file(struct fann * ann, char * filename, unsigned int max_epochs, unsigned int epochs_between_reports, float desired_error);&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Il ne reste plus ensuite qu'&#224; enregistrer la structure finale du r&#233;seau dans un fichier et &#224; d&#233;truire toute instance du r&#233;seau dans le programme. Les prototypes des fonctions utilis&#233;es &#224; cette fin sont respectivement les suivants :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;code class='spip_code' dir='ltr'&gt;bool fann_save(resource ann, string filename);&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;&lt;code class='spip_code' dir='ltr'&gt;void fann_destroy(struct fann * ann);&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;&lt;strong class=&quot;spip&quot;&gt;Utilisation du r&#233;seau&lt;/strong&gt;&lt;br&gt;
Cette seconde partie permettra d'&#233;tablir un r&#233;seau neuronal artificiel &#224; partir du fichier descriptif obtenu pr&#233;c&#233;demment apr&#232;s entra&#238;nement.&lt;/p&gt; &lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt; #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt; #include &quot;floatfann.h&quot;&lt;br /&gt; &lt;br /&gt; int main()&lt;br /&gt; {&lt;br /&gt; fann_type *calc_out;&lt;br /&gt; fann_type input[2];&lt;br /&gt; struct fann *ann = fann_create_from_file(&quot;xor_float.net&quot;);&lt;br /&gt; char ligne[10];&lt;br /&gt; int val;&lt;br /&gt; &lt;br /&gt; printf(&quot;Entree 1:&quot;);&lt;br /&gt; fgets(ligne,sizeof(ligne),stdin);&lt;br /&gt; sscanf(ligne,&quot;%d&quot;,&amp;val);&lt;br /&gt; input[0]=(fann_type) val;&lt;br /&gt; &lt;br /&gt; printf(&quot;\nEntree 2:&quot;);&lt;br /&gt; fgets(ligne,sizeof(ligne),stdin);&lt;br /&gt; sscanf(ligne,&quot;%d&quot;,&amp;val);&lt;br /&gt; input[1]=(fann_type) val;&lt;br /&gt; &lt;br /&gt; calc_out = fann_run(ann, input);&lt;br /&gt; &lt;br /&gt; printf(&quot;xor test (%f,%f) -&amp;gt; %f\n&quot;,&lt;br /&gt; input[0], input[1], *calc_out);&lt;br /&gt; &lt;br /&gt; fann_destroy(ann);&lt;br /&gt; return 0;&lt;br /&gt; }&lt;br /&gt;&lt;/code&gt;&lt;/div&gt; &lt;p class=&quot;spip&quot;&gt;Cette fois encore, les appels de fonctions sont gu&#232;re plus nombreux. L'allure finale du r&#233;seau obtenu apr&#232;s entra&#238;nement &#224; &#233;t&#233; retenu dans un fichier duquel sera charg&#233; le r&#233;seau. La fonction &lt;i class=&quot;spip&quot;&gt;fann_create_from_file&lt;/i&gt; est donc d'abord appell&#233;e &#224; cette fin.&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;code class='spip_code' dir='ltr'&gt;struct fann * fann_create_from_file(const char * configuration_file);&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Sans plus d'ennuis sont &#233;valu&#233;s ensuite les entr&#233;es fournis par l'utilisateur avec &lt;i class=&quot;spip&quot;&gt;fann_run&lt;/i&gt;.&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;code class='spip_code' dir='ltr'&gt;fann_type * fann_run(struct fann * ann, fann_type * input);&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Finalement, quitte le programme apr&#232;s avoir appell&#233; &lt;i class=&quot;spip&quot;&gt;fann_destroy&lt;/i&gt; qui lib&#232;re la m&#233;moire allou&#233;e dynamiquement au r&#233;seau neuronal artificiel.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;&lt;strong class=&quot;spip&quot;&gt;R&#233;sultat&lt;/strong&gt;&lt;br&gt;
Ainsi, si vous avez correctement entra&#238;n&#233; le r&#233;seau avec le programme
&lt;i class=&quot;spip&quot;&gt;entrainement.c&lt;/i&gt;, vous devriez obtenir un sc&#233;nario du genre lors de l'ex&#233;cution du programme ci-haut :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;pierre-luc@goll:~/ann$ ./exec &lt;br /&gt; Entree 1:1&lt;br /&gt; &lt;br /&gt; Entree 2:1&lt;br /&gt; xor test (1.000000,1.000000) -&amp;gt; 0.009030&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;On peut donc voir ici que la r&#233;ponse du syst&#232;me est plus que satisfaisante. En effet, il avait &#233;t&#233; convenu lors de la phase d'entra&#238;nement du r&#233;seau que l'erreur devait &#234;tre minimis&#233;e au moins jusqu'&#224; la valeur de 0.0001. Ainsi, apr&#232;s ex&#233;cution, voici ce qui avait &#233;t&#233; obtenu :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; pierre-luc@goll:~/ann$ ./entrainement&lt;br /&gt; Max epochs 500000. Desired error: 0.0001000000&lt;br /&gt; Epochs 1. Current error: 0.2508315742&lt;br /&gt; Epochs 350. Current error: 0.0000983779&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;L'erreur finale apr&#232;s 350 &#233;poques est de 0.0000983779 alors qu'elle &#233;tait de 0.2508315742 initialement. De plus, cette op&#233;ration s'effectue &#224; une vitesse impressionnante. La commande &lt;i class=&quot;spip&quot;&gt;time&lt;/i&gt; pour le programme d'exemple &lt;i class=&quot;spip&quot;&gt;entrainement&lt;/i&gt; sur un P4 1.5 ghz montrait ces r&#233;sultats :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; real 0m0.031s&lt;br /&gt; user 0m0.000s&lt;br /&gt; sys 0m0.000s&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Le temps r&#233;el passait parfois &#224; 0m0.010s mais se tenait g&#233;n&#233;ralement en dessous de 0m0.020s.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Consid&#233;rant &#224; la fois sa facilit&#233; d'utilisation ainsi que ses performances, &lt;i class=&quot;spip&quot;&gt;fann&lt;/i&gt; est tout indiqu&#233; pour un projet en phase de d&#233;veloppement ou en processus final. Il est certes beaucoup moins avantageux du c&#244;t&#233; p&#233;dagogique de l'utiliser, mais d'un autre, il est possible plus facilement par cet outil de s'attarder aux v&#233;ritables pr&#233;occupation du projet et &#224; sa recherche, donc d'apprendre.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Projet en suspend d'une biblioth&#232;que pour l'algorithme BPNN :&lt;br&gt;
&lt;a href=&quot;http://pierreluc.aqra.ca/projet/BackPropNN1/&quot; class=&quot;spip_url spip_out&quot;&gt;http://pierreluc.aqra.ca/projet/Bac...&lt;/a&gt;&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Manuel de r&#233;f&#233;rence pour FANN :&lt;br&gt;
&lt;a href=&quot;http://leenissen.dk/fann/html/index.html&quot; class=&quot;spip_url spip_out&quot;&gt;http://leenissen.dk/fann/html/index.html&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>



	<item>
		<title>Saisie d'images avec Video For Linux</title>
		<link>http://aqra.ca/Saisie-d-images-avec-Video-For</link>
		<guid isPermaLink="true">http://aqra.ca/Saisie-d-images-avec-Video-For</guid>
		<dc:date>2005-09-02T02:46:11Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Pierre-Luc Bacon</dc:creator>

<category domain="http://aqra.ca/-Programmation-">Programmation</category>


		<description>Dans certains cas, l'ajout d'un syst&#232;me de vision &#224; un robot s'av&#232;re un &#233;l&#233;ment essentiel &#224; son contr&#244;le. Cependant, l'implantation des techniques d'analyse de l'image peut exiger une programmation complexe ou l'usage de technologies sp&#233;cialis&#233;es. L'article qui suit traite du d&#233;veloppement d'un programme de traitement vid&#233;o sous Linux - ou plus pr&#233;cis&#233;ment de l'&#233;tape de capture de l'image - un choix qui, vous l'aurez devin&#233;, allie performance, stabilit&#233; et facilit&#233; de mise en oeuvre. &lt;br /&gt;Sommaire &lt;br /&gt;Avant (...)


-
&lt;a href="http://aqra.ca/-Programmation-" rel="directory"&gt;Programmation&lt;/a&gt;


		</description>


 <content:encoded>&lt;img src=&quot;http://aqra.ca/IMG/arton48.png&quot; alt=&quot;&quot; align=&quot;right&quot; width=&quot;95&quot; height=&quot;96&quot; class=&quot;spip_logos&quot; /&gt;
		&lt;div class='rss_chapo'&gt;Dans certains cas, l'ajout d'un syst&#232;me de vision &#224; un robot s'av&#232;re un &#233;l&#233;ment essentiel &#224; son contr&#244;le. Cependant, l'implantation des techniques d'analyse de l'image peut exiger une programmation complexe ou l'usage de technologies sp&#233;cialis&#233;es. L'article qui suit traite du d&#233;veloppement d'un programme de traitement vid&#233;o sous Linux - ou plus pr&#233;cis&#233;ment de l'&#233;tape de capture de l'image - un choix qui, vous l'aurez devin&#233;, allie performance, stabilit&#233; et facilit&#233; de mise en oeuvre.&lt;/div&gt;
		&lt;div class='rss_texte'&gt;&lt;div class='spip_document_473 spip_documents spip_documents_center' &gt;
&lt;a href=&quot;http://aqra.ca/IMG/png/seuillage-2.png&quot; type=&quot;image/png&quot; title='PNG - 107.4 ko'&gt;&lt;img src='http://aqra.ca/IMG/cache-150x113/seuillage-2-150x113-150x113.png' width='150' height='113' alt=&quot;PNG - 107.4 ko&quot; /&gt;&lt;/a&gt;
&lt;div class='spip_doc_titre' style='width:150px;'&gt;&lt;strong&gt;Seuillage du vert&lt;/strong&gt;&lt;/div&gt;
&lt;div class='spip_doc_descriptif' style='width:150px;'&gt;Programme d'analyse vid&#233;o en phase de d&#233;veloppement.&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Sommaire&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Avant toute chose, assurez-vous d'avoir &#224; la fois Video For Linux install&#233; sur votre syst&#232;me ainsi que le pilote en charge de votre camera web utilis&#233;e pour ce programme. S'il vous faut faire un choix concernant l'achat de mat&#233;riel, vous pouvez opter simplement pour la Quickcam Express de Logitech, peu co&#251;teuse et bien support&#233;e par le SE. &#192; ce sujet, consultez l'article de ce site &lt;a href=&quot;http://aqra.ca/Installation-de-la-Quickcam&quot; class=&quot;spip_in&quot;&gt;&#171; Installation de la Quickcam Express sous Linux &#187;&lt;/a&gt; pour obtenir des informations sur son installation. Pour ce qui est de V4L (Video For Linux), il serait fort &#233;tonnant que votre distribution ne l'int&#232;gre pas dans son noyau. Si toutefois tout semble indiquer que ce support est absent de votre syst&#232;me, la derni&#232;re version est disponible &#224; l'adresse &lt;a href=&quot;http://linux.bytesex.org/v4l2/&quot; class=&quot;spip_out&quot;&gt;http://linux.bytesex.org/v4l2/&lt;/a&gt;&lt;/p&gt; &lt;h2&gt;Ouverture de la cam&#233;ra&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Consid&#233;rant que la cam&#233;ra que nous souhaitons utiliser se situe en &lt;i class=&quot;spip&quot;&gt;/dev/videoX&lt;/i&gt;, son ouverture se fera par un appel &#224; la fonction &lt;i class=&quot;spip&quot;&gt;open(const char *chemin, int flags)&lt;/i&gt; avec ce chemin en param&#232;tre ainsi qu'un drapeau indiquant le mode d'acc&#232;s.&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; descrpFichier=open(&quot;/dev/video0&quot;, O_RDWR);&lt;br /&gt; if(descrpFichier &amp;lt; 0)&lt;br /&gt; {&lt;br /&gt; printf(&quot;\aAucun peripherique detecte\n&quot;);&lt;br /&gt; printf(&quot;Verifiez les droits d'acces a /dev/video0\n&quot;);&lt;br /&gt; exit(-1);&lt;br /&gt; }&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Si l'op&#233;ration est r&#233;ussie, la fonction &lt;i class=&quot;spip&quot;&gt;open&lt;/i&gt; retournera le descripteur du fichier ouvert. Dans le cas contraire, un message d'erreur s'affichera. Les causes peuvent &#234;tre multiples, mais la plupart du temps, le probl&#232;me proviendra des permissions accord&#233;es &#224; sur ce dispositif.&lt;/p&gt; &lt;h2&gt;Fermeture de la cam&#233;ra&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Intuitivement, la fermeture de la cam&#233;ra se fera par une fonction &lt;i class=&quot;spip&quot;&gt;close&lt;/i&gt;, prenant en param&#232;tre le descripteur de fichier obtenu par la fonction &lt;i class=&quot;spip&quot;&gt;open&lt;/i&gt;.&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; close(descrpFichier);&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;Requ&#234;te sur le dispositif&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;De mani&#232;re &#224; rendre l'application plus flexible devant le mat&#233;riel utilis&#233;, nous allons d'abord nous informer de ses possibilit&#233;s. Cette op&#233;ration se fera en effectuant un appel de type &lt;i class=&quot;spip&quot;&gt;ioctl VIDIOCGCAP&lt;/i&gt; qui retournera le r&#233;sultat dans une structure &lt;i class=&quot;spip&quot;&gt;video_capability&lt;/i&gt;.&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; struct video_capability vidcap;&lt;br /&gt; if (ioctl (descrpFichier, VIDIOCGCAP, &amp;vidcap) &amp;lt; 0)&lt;br /&gt; exit (-1);&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Les informations que contiendra la structure &lt;i class=&quot;spip&quot;&gt;vidcap&lt;/i&gt; sont les suivantes :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;thead&gt;&lt;tr class='row_first'&gt;&lt;th scope='col'&gt;&lt;strong class=&quot;spip&quot;&gt;struct video_capability&lt;/strong&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;
&lt;thead&gt;&lt;tr class='row_first'&gt;&lt;th scope='col'&gt;&lt;strong class=&quot;spip&quot;&gt;Nom&lt;/strong&gt;&lt;/th&gt;&lt;th scope='col'&gt;&lt;strong class=&quot;spip&quot;&gt;Description&lt;/strong&gt;&lt;/th&gt;&lt;th scope='col'&gt;&lt;strong class=&quot;spip&quot;&gt;Commentaires&lt;/strong&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;strong class=&quot;spip&quot;&gt;name[32]&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;i class=&quot;spip&quot;&gt;Nom[32]&lt;/i&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;&lt;strong class=&quot;spip&quot;&gt;type&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;i class=&quot;spip&quot;&gt;Type&lt;/i&gt;&lt;/td&gt;&lt;td&gt; Supporte la capture vid&#233;o ou non&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;strong class=&quot;spip&quot;&gt;channels&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;i class=&quot;spip&quot;&gt;Le nombre de canals&lt;/i&gt;&lt;/td&gt;&lt;td&gt; Si applicable (t&#233;l&#233;vision, radio)&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;&lt;strong class=&quot;spip&quot;&gt;audios&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;i class=&quot;spip&quot;&gt;Audio&lt;/i&gt;&lt;/td&gt;&lt;td&gt;Son disponible&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;strong class=&quot;spip&quot;&gt;maxheight&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;i class=&quot;spip&quot;&gt;Hauteur maximale (pixels)&lt;/i&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;&lt;strong class=&quot;spip&quot;&gt;maxwidth&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;i class=&quot;spip&quot;&gt;Largeur maximale (pixels)&lt;/i&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;strong class=&quot;spip&quot;&gt;minheight&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;i class=&quot;spip&quot;&gt;Hauteur minimale (pixels)&lt;/i&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;&lt;strong class=&quot;spip&quot;&gt;minwidth&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;i class=&quot;spip&quot;&gt;Largeur minimale (pixels)&lt;/i&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Pour nous assurer d'avoir acc&#232;s &#224; un dispositif supportant la saisie d'images, nous allons utiliser un drapeau sp&#233;cialement d&#233;fini dans &lt;i class=&quot;spip&quot;&gt;video for linux&lt;/i&gt; pour le comparer au champs &lt;i class=&quot;spip&quot;&gt;type&lt;/i&gt;.&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; if (!(vidcap.type &amp;&amp; VID_TYPE_CAPTURE))&lt;br /&gt; {&lt;br /&gt; printf (&quot;Le peripherique detecte ne supporte pas la capture\n&quot;);&lt;br /&gt; exit (-1);&lt;br /&gt; }&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;D'autres conditions pourraient &#234;tre test&#233;es pour s'assurer du bon fonctionnement du programme. Pour ce faire, V4L offre beaucoup d'autres drapeaux (&lt;i class=&quot;spip&quot;&gt;flags&lt;/i&gt;) qu'on a d'ailleurs document&#233;s ad&#233;quatement. [&lt;a href=&quot;http://aqra.ca/#nb6-1&quot; name=&quot;nh6-1&quot; id=&quot;nh6-1&quot; class=&quot;spip_note&quot; title='[1] Voir Video4Linux Kernel API Reference. Une version du document est (...)' &gt;1&lt;/a&gt;]&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;&lt;strong class=&quot;spip&quot;&gt;Param&#232;tres de l'image&lt;/strong&gt;&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;La zone de capture doit &#233;galement &#234;tre contenue dans une structure, cette fois, de type &lt;i class=&quot;spip&quot;&gt;video_window&lt;/i&gt;. &lt;i class=&quot;spip&quot;&gt;VIDIOCSWIN&lt;/i&gt; servira &#224; fixer la valeur de ses champs. Nous nous int&#233;resserons seulement qu'&#224; ceux-l&#224; :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;thead&gt;&lt;tr class='row_first'&gt;&lt;th scope='col'&gt;&lt;strong class=&quot;spip&quot;&gt;struct video_window&lt;/strong&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;
&lt;thead&gt;&lt;tr class='row_first'&gt;&lt;th scope='col'&gt;&lt;strong class=&quot;spip&quot;&gt;Champs&lt;/strong&gt;&lt;/th&gt;&lt;th scope='col'&gt;&lt;strong class=&quot;spip&quot;&gt;Commentaire&lt;/strong&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;x&lt;/td&gt;&lt;td&gt;Position en X&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;y&lt;/td&gt;&lt;td&gt;Position en Y&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;width&lt;/td&gt;&lt;td&gt;Largeur de l'image&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;height&lt;/td&gt;&lt;td&gt;Hauteur de l'image&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; struct video_window fenetre;&lt;br /&gt; fenetre.x = 0;&lt;br /&gt; fenetre.y = 0;&lt;br /&gt; fenetre.width = WIDTH;&lt;br /&gt; fenetre.height = HEIGHT;&lt;br /&gt; fenetre.clipcount = 0;&lt;br /&gt; fenetre.chromakey = 0;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; if (ioctl (descrpFichier, VIDIOCSWIN, &amp;fenetre) &amp;lt; 0)&lt;br /&gt; {&lt;br /&gt; perror (&quot;VIDIOCSWIN&quot;);&lt;br /&gt; exit (-1);&lt;br /&gt; }&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Si &lt;i class=&quot;spip&quot;&gt;VIDIOCSWIN&lt;/i&gt; a pu s'ex&#233;cuter, cela ne signifie pas pour autant que les valeurs pass&#233;es ont &#233;t&#233; support&#233;es. N'oubliez pas de v&#233;rifier le r&#233;sultat de l'op&#233;ration ! Pour conna&#238;tre la valeur des param&#232;tres qui y ont &#233;t&#233; d&#233;finis, nous appelleront &lt;i class=&quot;spip&quot;&gt;VIDIOCGWIN&lt;/i&gt; par &lt;i class=&quot;spip&quot;&gt;ioctl&lt;/i&gt; de nouveau.&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; if (ioctl (descrpFichier, VIDIOCGWIN, &amp;fenetre) &amp;lt; 0)&lt;br /&gt; exit (-1);&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;&lt;strong class=&quot;spip&quot;&gt;Aspect de l'image&lt;/strong&gt;&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Tout comme la fonction &lt;i class=&quot;spip&quot;&gt;VIDIOCSWIN&lt;/i&gt; permet de r&#233;gler certains param&#232;tres de l'image, &lt;i class=&quot;spip&quot;&gt;VIDIOCSPICT&lt;/i&gt; d&#233;terminera l'ajustement et son aspect : contraste, couleur, profondeur etc. Voyons l'organisation de la structure correspondante :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;thead&gt;&lt;tr class='row_first'&gt;&lt;th scope='col'&gt;&lt;strong class=&quot;spip&quot;&gt;struct video_picture&lt;/strong&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;
&lt;thead&gt;&lt;tr class='row_first'&gt;&lt;th scope='col'&gt;&lt;strong class=&quot;spip&quot;&gt;Champs&lt;/strong&gt;&lt;/th&gt;&lt;th scope='col'&gt;&lt;strong class=&quot;spip&quot;&gt;Commentaire&lt;/strong&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;brightness&lt;/td&gt;&lt;td&gt;Intensit&#233;&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;hue&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;color&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;contrast&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;whiteness&lt;/td&gt;&lt;td&gt;R&#233;glage des blancs&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;depth&lt;/td&gt;&lt;td&gt;Profondeur&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;palette&lt;/td&gt;&lt;td&gt;Mode de repr&#233;sentation des couleurs&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Le code qui permettra de modifier ces valeurs sera court :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; image.hue = hue;&lt;br /&gt; image.colour = colour;&lt;br /&gt; image.contrast = contrast;&lt;br /&gt; image.brightness = brightness;&lt;br /&gt; image.whiteness = whiteness;&lt;br /&gt; image.depth = depth;&lt;br /&gt; image.palette = PALETTE;&lt;br /&gt; if (ioctl (descrpFichier, VIDIOCSPICT, &amp;image) &amp;lt; 0)&lt;br /&gt; {&lt;br /&gt; perror (&quot;VIDIOCSPICT&quot;);&lt;br /&gt; exit (-1);&lt;br /&gt; }&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Comme expliqu&#233; plus-haut, nous nous assurerons d'avoir pu imposer ces valeurs avec la fonction &lt;i class=&quot;spip&quot;&gt;VIDIOCGPICT&lt;/i&gt; :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; if (ioctl (descrpFichier, VIDIOCGPICT, &amp;image) &amp;lt; 0)&lt;br /&gt; {&lt;br /&gt; perror (&quot;VIDIOCGPICT&quot;);&lt;br /&gt; exit (-1);&lt;br /&gt; }&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Par la suite, l'affichage des valeurs charg&#233;es peut se faire simplement ainsi :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; printf (&quot;Hue: %d\n&quot;, image.hue);&lt;br /&gt; printf (&quot;Color: %d\n&quot;, image.colour);&lt;br /&gt; printf (&quot;Contrast: %d\n&quot;, image.contrast);&lt;br /&gt; printf (&quot;Brightness: %d\n&quot;, image.brightness);&lt;br /&gt; printf (&quot;Whiteness: %d\n&quot;, image.whiteness);&lt;br /&gt; printf (&quot;Depth: %d\n&quot;, image.depth);&lt;br /&gt; printf (&quot;Taille du buffer: %d octets\n&quot;, mbuf.size);&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;Capture en tampon double&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Nous voil&#224; finalement rendu &#224; l'&#233;tape quasi finale du processus : l'obtention de l'image depuis le pilote de la cam&#233;ra. Comme le temps d'occupation du processeur est une denr&#233;e pr&#233;ciseuse en informatique, nous tacherons ici &#224; optimiser les op&#233;rations en implantant un syst&#232;me d'espace m&#233;moire &#224; tampon double de mani&#232;re &#224; &#233;viter de perdre des images. Notez aussi que les donn&#233;es ne transiteront pas ici directement depuis le &lt;i class=&quot;spip&quot;&gt;framebuffer&lt;/i&gt; de la carte vid&#233;o mais passeront plut&#244;t par un espace tampon.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;L'id&#233;e du principe de capture &#224; tampons multiples est de fournir en tout temps au pilote du p&#233;riph&#233;rique un espace m&#233;moire pour d&#233;poser son image. Cela se fait donc d'abord en ex&#233;cutant une s&#233;rie de requ&#234;tes VIDIOCMCAPTURE qui seront mises en file par le pilote. Un appel VIDIOCSYNC permettra ensuite d'attendre jusqu'&#224; la lib&#233;ration de l'image. La s&#233;quence des requ&#234;tes, plac&#233;e dans un boucle infinie, devrait &#234;tre la suivante :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; VIDIOCMCAPTURE(0)&lt;br /&gt; VIDIOCMCAPTURE(1)&lt;br /&gt; VIDIOSYNC(0) /*Attends l'arriv&#233;e des donn&#233;es pour le buffer 0*&quot;&lt;br /&gt; [traitement des donn&#233;es du buffer 0]&lt;br /&gt; VIDIOCMCAPTURE(0)/*Le buffer 0 est remis dans la file*/&lt;br /&gt; VIDIOSYNC(1)/*Le buffer 1 est en remplissage*/&lt;br /&gt; [traitement des donn&#233;es du buffer 1]&lt;br /&gt; VIDIOCMCAPTURE /*Le buffer 1 est remis dans la file*/&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;L'image peut ensuite &#234;tre retrouv&#233;e en m&#233;moire en effectuant la somme du pointeur sur la MMAP plus l'&#233;l&#233;ment &lt;i class=&quot;spip&quot;&gt;offsets&lt;/i&gt; de la sturcture &lt;i class=&quot;spip&quot;&gt;video_mbuf&lt;/i&gt;.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Ex :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; unsigned char *buf;&lt;br /&gt; buf=mmapptr+mbuf.offsets[num_image]&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;Saisie des images et copie dans un &quot;buffer&quot;&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;La fonction pr&#233;sent&#233;e ci-dessous tire partie d'un syst&#232;me &#224; base de pointeurs de fonction. En effet, un pointeur sur une fonction capable d'effectuer le traitement de l'image sera pass&#233; en argument. Ce pointeur pourra ensuite &#234;tre utilis&#233; pour appeller la fonction appropri&#233;e lors du passage de l'image au programme.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Puisque nous utilisons l'interface MMAP, nous devrons d'abord obtenir des informations sur la taille du &lt;i class=&quot;spip&quot;&gt;buffer&lt;/i&gt; en MMAP et la position des images dans cet espace.&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; if(ioctl(descrpFichier, VIDIOCGMBUF, &amp;mbuf)&amp;lt;0)&lt;br /&gt; {&lt;br /&gt; perror(&quot;VIDIOCGMBUF&quot;);&lt;br /&gt; exit(-1);&lt;br /&gt; }&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Nous obtiendrons effectivement cet espace en MMAP par la suite de cette mani&#232;re :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; ptr = (unsigned char*)mmap(0, mbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED,descrpFichier,0);&lt;br /&gt; if(ptr==(unsigned char*) -1){&lt;br /&gt; perror(&quot;mmap&quot;);&lt;br /&gt; exit(-1);&lt;br /&gt; }&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Nous voyons donc ici, plus-haut, que l'&#233;l&#233;ment &lt;i class=&quot;spip&quot;&gt;size&lt;/i&gt; de la structure mbuf inform&#233;e plus t&#244;t par l'appel &lt;i class=&quot;spip&quot;&gt;VIDIOCGMBUF&lt;/i&gt; est utilis&#233; pour d&#233;terminer l'espace n&#233;cessaire pour un tampon accessible en lecture et en &#233;criture sur notre p&#233;riph&#233;rique, d&#233;termin&#233; par &lt;i class=&quot;spip&quot;&gt;descrpFichier&lt;/i&gt;.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Vient maitenant une &#233;tape n&#233;cessaire avant d'effectuer nos appels aux fonctions de capture de V4L : nous devons renseigner une structure de type &lt;i class=&quot;spip&quot;&gt;video_mmap&lt;/i&gt; dans ses champs &lt;i class=&quot;spip&quot;&gt;height&lt;/i&gt;, &lt;i class=&quot;spip&quot;&gt;width&lt;/i&gt;, et &lt;i class=&quot;spip&quot;&gt;format&lt;/i&gt;. Cette &#233;tape est sans commentaires sp&#233;ciaux, &#224; l'exception du conseil suivant : il est profitable pour une question d'efficacit&#233; d'utiliser des macros (&lt;i class=&quot;spip&quot;&gt;defines&lt;/i&gt;) pour donner la valeur &#224; certains param&#232;tres tels que la taille de l'image, le format etc. Ainsi, les mots en majuscules dans le bout de code suivant sont d&#233;finis dans le fichier d'ent&#234;te par les valeurs souhait&#233;es.&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; mapbuf.height = HEIGHT ;&lt;br /&gt; mapbuf.width = WIDTH;&lt;br /&gt; mapbuf.format = PALETTE;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Comme expliqu&#233; dans la section &lt;i class=&quot;spip&quot;&gt;&#171; capture en tampon double &#187;&lt;/i&gt;, nous effecturons une s&#233;rie d'appels VIDIOCMCAPTURE selon le nombre de &lt;i class=&quot;spip&quot;&gt;buffers&lt;/i&gt; support&#233;s par le pilote. Ceux-ci seront plac&#233;s en file avant d'&#234;tre synchronis&#233;s par la fonction &lt;i class=&quot;spip&quot;&gt;VIDIOCSYNC&lt;/i&gt;.&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; for(image=0; image&amp;lt;mbuf.frames; image++)&lt;br /&gt; {&lt;br /&gt; mapbuf.frame = image;&lt;br /&gt; if(ioctl(descrpFichier, VIDIOCMCAPTURE, &amp;mapbuf))&lt;br /&gt; {&lt;br /&gt; perror(&quot;VIDIOCMCAPTURE&quot;);&lt;br /&gt; exit(-1);&lt;br /&gt; }&lt;br /&gt; }&lt;br /&gt; image=0;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;La variable &lt;i class=&quot;spip&quot;&gt;image&lt;/i&gt;, aura &#233;t&#233; d&#233;clar&#233;e plus-haut pour indiquer le nombre d'images pouvant &#234;tre captur&#233;s par le pilote : c'est l'indicateur du nombre de &lt;i class=&quot;spip&quot;&gt;buffers&lt;/i&gt;. La valeur de cette varible est ensuite chang&#233;e &#224; 0 car nous la r&#233;utiliserons comme argument &#224; la fonction VIDIOCSYNC. Dans une boucle, nous mettons en application le principe expliqu&#233; dans le paragraphe pr&#233;c&#233;dent :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; while(nbcapture&amp;lt;rep)&lt;br /&gt; {&lt;br /&gt; i=-1;&lt;br /&gt; while(i&amp;lt;0){ /*Tant qu'on obtient une erreur, l'appel doit etre repete. */&lt;br /&gt; /*On verifie que la fonction a reussi et qu'il n'y a pas eu de signals qui ont interrompu l'appel.*/&lt;br /&gt; i=ioctl(descrpFichier, VIDIOCSYNC, &amp;image);&lt;br /&gt; if(i &amp;lt; 0 || errno == EINTR)&lt;br /&gt; {&lt;br /&gt; if(i&amp;lt;0)&lt;br /&gt; {&lt;br /&gt; perror(&quot;VIDIOCSYNC&quot;);&lt;br /&gt; printf(&quot;Le programme doit quitter\n\a&quot;);&lt;br /&gt; exit(-1);&lt;br /&gt; }&lt;br /&gt; continue;&lt;br /&gt; }&lt;br /&gt; break; /*La sync. s'est bien deroule. On sort de la boucle*/&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; posImg=ptr+mbuf.offsets[image];&lt;br /&gt; /*La fonction de traitement peut maintenant etre appellee avec posImg comme argument*/&lt;br /&gt; printf(&quot;Adresse image: %p\n&quot;, posImg);&lt;br /&gt; ptrfonction(posImg,HEIGHT,WIDTH);&lt;br /&gt; /*On remet le buffer a la disposition du driver*/&lt;br /&gt; &lt;br /&gt; mapbuf.frame = image;&lt;br /&gt; if(ioctl(descrpFichier, VIDIOCMCAPTURE, &amp;mapbuf)&amp;lt;0)&lt;br /&gt; {&lt;br /&gt; perror(&quot;VIDIOCMCAPTURE&quot;);&lt;br /&gt; printf(&quot;L'application doit quitter\n\a&quot;);&lt;br /&gt; closeCam();&lt;br /&gt; exit(-1);&lt;br /&gt; }&lt;br /&gt; image++;&lt;br /&gt; &lt;br /&gt; if(image&amp;gt;mbuf.frames)image=0;&lt;br /&gt; &lt;br /&gt; nbcapture++;&lt;br /&gt; &lt;br /&gt; }&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Nous effectuons d'abord dans un premier passage la synchronisation de l'image 0 avec VIDIOCSYNC plac&#233; dans une boucle conditionelle qui v&#233;rifie que la fonction soit bel et bien parvenue &#224; effectuer sa t&#226;che sans avoir &#233;t&#233; interrompue par un signal ou un probl&#232;me quelconque. Nous pouvons alors ensuite recueillir notre premi&#232;re image par le simple calcul suivant :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; posImg=ptr+mbuf.offsets[image];&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Suite &#224; cette op&#233;ration, le pointeur de fonction utilis&#233; en param&#232;tre de la fonction de capture peut &#234;tre utilis&#233; de la sorte :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; ptrfonction(posImg,HEIGHT,WIDTH);&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Nous pouvons maintenant remettre le &lt;i class=&quot;spip&quot;&gt;buffer&lt;/i&gt; courant &#224; la disposition du driver en utilisant de nouveau &lt;i class=&quot;spip&quot;&gt;VIDIOCMCAPTURE&lt;/i&gt;.&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; mapbuf.frame = image;&lt;br /&gt; if(ioctl(descrpFichier, VIDIOCMCAPTURE, &amp;mapbuf)&amp;lt;0)&lt;br /&gt; {&lt;br /&gt; perror(&quot;VIDIOCMCAPTURE&quot;);&lt;br /&gt; printf(&quot;L'application doit quitter\n\a&quot;);&lt;br /&gt; closeCam();&lt;br /&gt; exit(-1);&lt;br /&gt; }&lt;br /&gt; image++;&lt;br /&gt; &lt;br /&gt; if(image&amp;gt;mbuf.frames)image=0;&lt;br /&gt; &lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Le champs &lt;i class=&quot;spip&quot;&gt;frame&lt;/i&gt; de la structure &lt;i class=&quot;spip&quot;&gt;mapbuf&lt;/i&gt; de type &lt;i class=&quot;spip&quot;&gt;video_mmap&lt;/i&gt; est d&#233;fini &#224; la l'indicateur de l'image venant d'&#234;tre utilis&#233;e. Finalement, la derni&#232;re ligne s'assure de remettre la valeur de &lt;i class=&quot;spip&quot;&gt;image&lt;/i&gt; &#224; 0 si l'on a d&#233;pass&#233; le nombre d'images en attente support&#233;.&lt;/p&gt; &lt;h2&gt; Lecture des donn&#233;es de l'image RGB et &#233;criture d'un fichier PPM &lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Une image saisie en format RGB24 peut &#234;tre facilement interpr&#233;t&#233;e : un pixel &#233;tant d&#233;crit par un triplet de valeurs dans l'ordre BGR. Le pointeur de notre image, appelons-le &lt;i class=&quot;spip&quot;&gt;posImg&lt;/i&gt;, pointe donc sur la valeur B du premier pixel. Pour effectuer cette op&#233;ration sur la totalit&#233; de l'image, deux boucle &lt;i class=&quot;spip&quot;&gt;for&lt;/i&gt; seront utilis&#233;es : une premi&#232;re lisant tous les pixels de 1 &#224; n pour une ligne et une seconde boucle passant d'une ligne &#224; l'autre.&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;&lt;br /&gt; void extractPix(unsigned char* imgbuffer, int hauteur, int largeur)&lt;br /&gt; {&lt;br /&gt; printf(&quot;En cours d'ecriture de l'image...\n&quot;);&lt;br /&gt; fp = fopen(&quot;capturecam.ppm&quot;, &quot;w&quot;);&lt;br /&gt; if(fp==NULL)&lt;br /&gt; {&lt;br /&gt; printf(&quot;Impossible d'ouvrir le fichier\n&quot;);&lt;br /&gt; exit(-1);&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; fprintf(fp, &quot;P6\n%d %d\n255\n&quot;,largeur, hauteur);&lt;br /&gt; for(y=0;y&amp;lt;hauteur; y++)&lt;br /&gt; { &lt;br /&gt; for(x=0; x&amp;lt;largeur; x++)&lt;br /&gt; {&lt;br /&gt; b=imgbuffer[p];p++;&lt;br /&gt; g=imgbuffer[p];p++;&lt;br /&gt; r=imgbuffer[p];p++;&lt;br /&gt; putc(r, fp);&lt;br /&gt; putc(g, fp);&lt;br /&gt; putc(b, fp); &lt;br /&gt; }&lt;br /&gt; }&lt;br /&gt; fflush(fp);&lt;br /&gt; fclose(fp);&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Ce code montre l'ouverture d'un fichier de type PPM [&lt;a href=&quot;http://aqra.ca/#nb6-2&quot; name=&quot;nh6-2&quot; id=&quot;nh6-2&quot; class=&quot;spip_note&quot; title='[2] Pour plus de renseignements sur la manipulation d&amp;#39;images en format PPM, (...)' &gt;2&lt;/a&gt;] et de la scrutation de l'image en m&#233;moire par une double boucle copiant les valeurs RGB dans l'ordre inverse dans les variables correspondantes de type &lt;i class=&quot;spip&quot;&gt;unsigned char&lt;/i&gt;. Portez attention ici au prototype de cette fonction qui respecte la d&#233;claration du pointeur de fonctions dans l'&#233;tape de capture de l'image.&lt;/p&gt; &lt;h2&gt; Qu'est-ce qu'est la MMAP ?&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;MMAP signifie &quot;memory map&quot; en langue anglaise. Cette fonction sert &#224; repr&#233;senter de mani&#232;re localis&#233;e (ou &quot;projetter&quot;) un fichier dans une zone m&#233;moire selon une indication de longueur de l'espace requis et de positionnement par rapport au descripteur d'un fichier. Vous remarquerez donc ici qu'en la d&#233;finition de &quot;fichier&quot; sous syst&#232;me UNIX, nous entendons &#233;galement &quot;p&#233;riph&#233;rique&quot;. La MMAP est donc un moyen de recuillir les donn&#233;es d'un certains flux dans une zone m&#233;moire de mani&#232;re organis&#233;e.&lt;/p&gt;&lt;/div&gt;
		&lt;hr /&gt;
		&lt;div class='rss_notes'&gt;&lt;p class=&quot;spip_note&quot;&gt;[&lt;a href=&quot;http://aqra.ca/#nh6-1&quot; name=&quot;nb6-1&quot; class=&quot;spip_note&quot; title=&quot;info notes 6-1&quot;&gt;1&lt;/a&gt;] Voir &lt;i class=&quot;spip&quot;&gt;Video4Linux Kernel API Reference&lt;/i&gt;. Une version du document est accessible sur ce site : www.aqra.ca/pierre-luc/camapp/API.html&lt;/p&gt; &lt;p class=&quot;spip_note&quot;&gt;[&lt;a href=&quot;http://aqra.ca/#nh6-2&quot; name=&quot;nb6-2&quot; class=&quot;spip_note&quot; title=&quot;info notes 6-2&quot;&gt;2&lt;/a&gt;] Pour plus de renseignements sur la manipulation d'images en format PPM, r&#233;f&#233;rez-vous &#224; l'article 35 sur ce site intitul&#233; &quot;Conversion d'images couleur en niveaux de gris&quot;. http://www.aqra.ca/article.php3 ?id_article=35&lt;/p&gt;&lt;/div&gt;
		
		</content:encoded>


		
		<enclosure url="http://aqra.ca/IMG/c/camera.c" length="5680" type="text/x-csrc" />
		
		<enclosure url="http://aqra.ca/IMG/h/camera.h" length="1747" type="text/x-chdr" />
		

	</item>



	<item>
		<title>Librairie en C18 pour LCD</title>
		<link>http://aqra.ca/Librairie-en-C18-pour-LCD</link>
		<guid isPermaLink="true">http://aqra.ca/Librairie-en-C18-pour-LCD</guid>
		<dc:date>2005-06-03T02:56:52Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Fran&#231;ois Duval</dc:creator>

<category domain="http://aqra.ca/-Programmation-">Programmation</category>


		<description>Cette librairie a &#233;t&#233; &#233;crite pour faciliter l'incorporation d'un afficheur LCD &#224; un projet. Elle est &#233;crite en C18, pour les PICs de la famille 18F. Plut&#244;t que de faire un grand discours, regardons le code : &lt;br /&gt; ; //Librairie pour afficheur LCD 16*1 charact&#232;res //R&#233;vision du 01/06/2005 &lt;br /&gt;//N.B. Le LCD 16*1 est en fait deux LCDs 8*1 sur la m&#234;me ligne //c'est pourquoi on doit choisir entre ligne 1 et 2 (chaque &#189; &#233;cran) &lt;br /&gt;/* D&#233;finitions des pins pour le LCD &#192; ajuster selon l'application &lt;br /&gt;LCD =&gt; PIC &lt;br /&gt;14 =&gt; RD7 (...)


-
&lt;a href="http://aqra.ca/-Programmation-" rel="directory"&gt;Programmation&lt;/a&gt;


		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p class=&quot;spip&quot;&gt;Cette librairie a &#233;t&#233; &#233;crite pour faciliter l'incorporation d'un afficheur LCD &#224; un projet. Elle est &#233;crite en C18, pour les PICs de la famille 18F. Plut&#244;t que de faire un grand discours, regardons le code :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;//Librairie pour afficheur LCD 16*1 charact&#232;res&lt;br /&gt; //R&#233;vision du 01/06/2005&lt;br /&gt; &lt;br /&gt; //N.B. Le LCD 16*1 est en fait deux LCDs 8*1 sur la m&#234;me ligne&lt;br /&gt; //c'est pourquoi on doit choisir entre ligne 1 et 2 (chaque &#189; &#233;cran) &lt;br /&gt; &lt;br /&gt; /*&lt;br /&gt; D&#233;finitions des pins pour le LCD&lt;br /&gt; &#192; ajuster selon l'application&lt;br /&gt; &lt;br /&gt; LCD =&amp;gt; PIC&lt;br /&gt; -----------&lt;br /&gt; 14 =&amp;gt; RD7&lt;br /&gt; 13 =&amp;gt; RD6 &lt;br /&gt; 12 =&amp;gt; RD5&lt;br /&gt; 11 =&amp;gt; RD4&lt;br /&gt; 10 =&amp;gt; RD3&lt;br /&gt; 9 =&amp;gt; RD2&lt;br /&gt; 8 =&amp;gt; RD1&lt;br /&gt; 7 =&amp;gt; RD0&lt;br /&gt; 6 =&amp;gt; RC4 (En) &lt;br /&gt; 5 =&amp;gt; RC5 (RW)&lt;br /&gt; 4 =&amp;gt; RC3 (RS)&lt;br /&gt; 3 =&amp;gt; x (contraste)&lt;br /&gt; 2 =&amp;gt; x (GND)&lt;br /&gt; 1 =&amp;gt; x (5V)&lt;br /&gt; */&lt;br /&gt; &lt;br /&gt; #define LCDdata PORTD&lt;br /&gt; #define TRIS_LCDdata TRISD&lt;br /&gt; #define LCDenable PORTCbits.RC4&lt;br /&gt; #define TRIS_LCDenable TRISCbits.TRISC4&lt;br /&gt; #define LCDrs PORTCbits.RC3&lt;br /&gt; #define TRIS_LCDrs TRISCbits.TRISC3&lt;br /&gt; #define LCDrw PORTCbits.RC5&lt;br /&gt; #define TRIS_LCDrw TRISCbits.TRISC5&lt;br /&gt; &lt;br /&gt; //Defines pour config du lcd&lt;br /&gt; #define clear 1&lt;br /&gt; #define home 2&lt;br /&gt; #define cursorON 3&lt;br /&gt; #define cursorOFF 4&lt;br /&gt; #define shift 5&lt;br /&gt; &lt;br /&gt; //D&#233;lais&lt;br /&gt; #define wait Delay10KTCYx(1)&lt;br /&gt; #define longwait Delay10KTCYx(15) &lt;br /&gt; #define shortwait Delay1KTCYx(1)&lt;br /&gt; #define Delay_05ms Delay10TCYx(250)&lt;br /&gt; &lt;br /&gt; //variables utilis&#233;es ds les routines&lt;br /&gt; int t; &lt;br /&gt; int o;&lt;br /&gt; &lt;br /&gt; //fonction d'initialisation de l'&#233;cran&lt;br /&gt; void initlcd (void)&lt;br /&gt; {&lt;br /&gt; LCDdata = 0b00000000; //toutes les pins de donn&#233;es &#224; 0&lt;br /&gt; LCDrw = 0;&lt;br /&gt; LCDenable = 0; //enable &#224; 0&lt;br /&gt; LCDrs = 0; //Register Select &#224; 0 (configuration) &lt;br /&gt; &lt;br /&gt; longwait;&lt;br /&gt; &lt;br /&gt; //display ON&lt;br /&gt; LCDdata = 0b00001111;&lt;br /&gt; wait;&lt;br /&gt; LCDenable = 1;&lt;br /&gt; wait;&lt;br /&gt; LCDenable = 0;&lt;br /&gt; wait;&lt;br /&gt; &lt;br /&gt; // mode 8 bit&lt;br /&gt; LCDdata = 0b00000001; &lt;br /&gt; wait;&lt;br /&gt; LCDenable = 1;&lt;br /&gt; wait;&lt;br /&gt; LCDenable = 0;&lt;br /&gt; wait;&lt;br /&gt; &lt;br /&gt; // effacer l'&#233;cran&lt;br /&gt; LCDdata = 0b00111000; &lt;br /&gt; wait;&lt;br /&gt; LCDenable = 1;&lt;br /&gt; wait;&lt;br /&gt; LCDenable = 0;&lt;br /&gt; wait;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; //fonction pour choisir entre quelle ligne d'&#233;cran&lt;br /&gt; void line (int x)&lt;br /&gt; {&lt;br /&gt; if (x == 1)&lt;br /&gt; {&lt;br /&gt; //set display adress au d&#233;but de l'&#233;cran (ligne 1)&lt;br /&gt; LCDrs = 0;&lt;br /&gt; LCDrw = 0;&lt;br /&gt; LCDdata = 0x80; &lt;br /&gt; wait;&lt;br /&gt; LCDenable = 1;&lt;br /&gt; wait;&lt;br /&gt; LCDenable = 0;&lt;br /&gt; wait;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; if (x == 2)&lt;br /&gt; {&lt;br /&gt; //set display adress au 9e charact&#232;re (ligne 2)&lt;br /&gt; LCDrs = 0;&lt;br /&gt; LCDrw = 0;&lt;br /&gt; LCDdata = 0xC0; &lt;br /&gt; wait;&lt;br /&gt; LCDenable = 1;&lt;br /&gt; wait;&lt;br /&gt; LCDenable = 0;&lt;br /&gt; wait;&lt;br /&gt; }&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; //configuration de l'&#233;cran (efface, home, etc)&lt;br /&gt; void configlcd (int config)&lt;br /&gt; {&lt;br /&gt; if (config == clear)&lt;br /&gt; {&lt;br /&gt; //efface l'&#233;cran&lt;br /&gt; LCDrs = 0;&lt;br /&gt; LCDdata = 0b00000001; &lt;br /&gt; shortwait;&lt;br /&gt; LCDenable = 1;&lt;br /&gt; shortwait;&lt;br /&gt; LCDenable = 0;&lt;br /&gt; wait; &lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; if (config == home)&lt;br /&gt; {&lt;br /&gt; //curseur et &#233;cran home&lt;br /&gt; LCDrs = 0;&lt;br /&gt; LCDdata = 0b00000011; &lt;br /&gt; wait;&lt;br /&gt; LCDenable = 1;&lt;br /&gt; wait;&lt;br /&gt; LCDenable = 0;&lt;br /&gt; wait; &lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; if (config == cursorON)&lt;br /&gt; {&lt;br /&gt; //curseur ON&lt;br /&gt; LCDrs = 0;&lt;br /&gt; LCDdata = 0b00001111; &lt;br /&gt; wait;&lt;br /&gt; LCDenable = 1;&lt;br /&gt; wait;&lt;br /&gt; LCDenable = 0;&lt;br /&gt; wait;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; if (config == cursorOFF)&lt;br /&gt; {&lt;br /&gt; //curseur OFF&lt;br /&gt; LCDrs = 0;&lt;br /&gt; LCDdata = 0b00001100; &lt;br /&gt; wait;&lt;br /&gt; LCDenable = 1;&lt;br /&gt; wait;&lt;br /&gt; LCDenable = 0;&lt;br /&gt; wait;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; if (config == shift)&lt;br /&gt; {&lt;br /&gt; //shift display&lt;br /&gt; LCDrs = 0;&lt;br /&gt; LCDdata = 0b00011000; &lt;br /&gt; wait;&lt;br /&gt; LCDenable = 1;&lt;br /&gt; wait;&lt;br /&gt; LCDenable = 0;&lt;br /&gt; wait;&lt;br /&gt; }&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; //affichage d'un charact&#232;re sur l'&#233;cran&lt;br /&gt; void printlcd (char text)&lt;br /&gt; {&lt;br /&gt; LCDrs = 1;&lt;br /&gt; shortwait;&lt;br /&gt; LCDdata = text; // print text&lt;br /&gt; shortwait;&lt;br /&gt; LCDenable = 1;&lt;br /&gt; shortwait;&lt;br /&gt; LCDenable = 0;&lt;br /&gt; LCDdata = 0b00000000; //remet toutes les sorties &#224; 0&lt;br /&gt; LCDrs = 0; &lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; //affichage d'une chaine de charact&#232;res sur l'&#233;cran&lt;br /&gt; void printstringlcd (char *str)&lt;br /&gt; {&lt;br /&gt; line(1);&lt;br /&gt; &lt;br /&gt; for(t=0; t&amp;lt;=7; ++t) //imprime les premiers charact&#232;res&lt;br /&gt; {&lt;br /&gt; printlcd(str[t]);&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; line(2);&lt;br /&gt; &lt;br /&gt; for(t=8; t&amp;lt;=15; ++t) //imprime les derniers charact&#232;res&lt;br /&gt; {&lt;br /&gt; printlcd(str[t]); &lt;br /&gt; }&lt;br /&gt; }&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Le code source de la librairie vous &#233;tant maintenant connu, voici un petit exemple de comment l'utiliser pour afficher &quot;Bonjour&quot; sur votre &#233;cran LCD.&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;//includes&lt;br /&gt; #include &amp;lt;p18f452.h&amp;gt; // for ports declarations&lt;br /&gt; #include &amp;lt;delays.h&amp;gt; // for delay routines&lt;br /&gt; #include &amp;lt;timers.h&amp;gt; //for interrupts&lt;br /&gt; #include &quot;liblcd.c&quot;&lt;br /&gt; &lt;br /&gt; //variables&lt;br /&gt; char bonjour[] = &quot; Bonjour ! &quot;;&lt;br /&gt; &lt;br /&gt; //fonction principale du programme&lt;br /&gt; void main ()&lt;br /&gt; {&lt;br /&gt; //On d&#233;sactive l'acquisition analogique&lt;br /&gt; ADCON1=6; &lt;br /&gt; &lt;br /&gt; //d&#233;finitions des I/O&lt;br /&gt; TRIS_LCDdata = 0; &lt;br /&gt; TRIS_LCDenable = 0;&lt;br /&gt; TRIS_LCDrw = 0;&lt;br /&gt; TRIS_LCDrs = 0;&lt;br /&gt; &lt;br /&gt; initlcd();&lt;br /&gt; printstringlcd(bonjour);&lt;br /&gt; &lt;br /&gt; while(1)&lt;br /&gt; {&lt;br /&gt; }&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; //config du PIC&lt;br /&gt; #pragma config OSC = HS&lt;br /&gt; #pragma config PWRT = ON&lt;br /&gt; #pragma config WDT = OFF&lt;br /&gt; #pragma config BOR = ON&lt;br /&gt; #pragma config BORV = 42&lt;br /&gt; #pragma config LVP = OFF&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Tout ce qui est &#233;crit ci-dessus est pour un afficheur 16*1 et pour un PIC18F452. Vous pouvez bien sur changer le mod&#232;le de PIC sans probl&#232;me, en ajustant les pins et le &lt;i class=&quot;spip&quot;&gt;#include&lt;/i&gt; en haut du texte. Pour changer le mod&#232;le de LCD (par exemple pour utiliser un 16*2), il suffira de changer les valeurs des limites de ligne dans la fonction &lt;i class=&quot;spip&quot;&gt;printstringlcd&lt;/i&gt;.&lt;/p&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>



	<item>
		<title>Conversion d'images couleur en niveaux de gris</title>
		<link>http://aqra.ca/Conversion-d-images-couleur-en</link>
		<guid isPermaLink="true">http://aqra.ca/Conversion-d-images-couleur-en</guid>
		<dc:date>2005-01-17T22:51:53Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Pierre-Luc Bacon</dc:creator>

<category domain="http://aqra.ca/-Programmation-">Programmation</category>

		<dc:subject>traitement image</dc:subject>
		<dc:subject>niveaux de gris</dc:subject>
		<dc:subject>ppm</dc:subject>

		<description>Programme simple de conversion des couleurs d'un fichier PPM en sa repr&#233;sentation en niveaux de gris.

-
&lt;a href="http://aqra.ca/-Programmation-" rel="directory"&gt;Programmation&lt;/a&gt;

/ 
&lt;a href="http://aqra.ca/+-traitement-image-+" rel="tag"&gt;traitement image&lt;/a&gt;, 
&lt;a href="http://aqra.ca/+-niveaux-de-gris-+" rel="tag"&gt;niveaux de gris&lt;/a&gt;, 
&lt;a href="http://aqra.ca/+-ppm-+" rel="tag"&gt;ppm&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_chapo'&gt;Mon activit&#233; &#233;ditoriale sur ce site a &#233;t&#233; r&#233;duite ce dernier mois en raison de l'&#233;criture d'un programme de traitement vid&#233;o. Cet article est le premier d'une s&#233;rie qui s'attardera &#224; effectuer diverses op&#233;rations de capture et de traitement de l'image. Dans ces lignes sera pr&#233;sent&#233; un programme de conversion d'images en format PPM vers le format PGM.&lt;/div&gt;
		&lt;div class='rss_texte'&gt;&lt;p class=&quot;spip&quot;&gt;L'algorithme de transformation de l'espace des valeurs rouge, vert et bleu en sa repr&#233;sentation par niveaux de gris est d'une grande simplicit&#233; &#224; r&#233;aliser. Son importance en est pas moins consid&#233;rable puisque l'espace de niveaux de gris d'une image est une &#233;tape essentielle de tous traitements car la complexit&#233; du programme et le temps de calcul s'en trouvent r&#233;duits. Cela permettra par exemple de tirer profit des filtres convolutifs du genre Prewitt ou Sobel.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Pour convertir les valeurs RGB, il suffit d'appliquer la formule suivante :&lt;/p&gt; &lt;div class=&quot;texteencadre-spip&quot;&gt;Y=R*0,299+G*0,587+B*0,114&lt;/div&gt;
&lt;p class=&quot;spip&quot;&gt;o&#249; Y exprime le niveau de gris pour un pixel donn&#233;&lt;/p&gt; &lt;h2&gt;Formats PNM&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Ce type de format permet de coder une image dans sa plus simple expression. Le terme &#171; PNM &#187; est une g&#233;n&#233;ralisation d'un type d'images regroupant les formats r&#233;els &#171; PBM &#187;, &#171; PGM &#187; et &#171; PPM &#187;. Ces extensions servent &#224; d&#233;finir trois types d'images : binaris&#233;es pour le PBM, en niveaux de gris pour le PGM et en couleur pour le PPM. Tous les fichiers PNM se structurent de la m&#234;me mani&#232;re &#224; l'exception pr&#232;s du format PBM. Tout d'abord, une ent&#234;te d&#233;termine le type par un &#171; chiffre magique &#187; (indicateur commen&#231;ant par P), les dimensions de l'image et son intensit&#233; maximale. Les lignes ne peuvent d&#233;passer plus de 70 charact&#232;res et tous commentaires doivent &#234;tre pr&#233;c&#233;d&#233;s du symbole &#171; # &#187;. Les formats PNM n'introduisent aucune compression les pixels : il suffit donc d'en exprimer la valeur par RVB pour le PPM, niveau de gris dans le cas du PGM ou simplement avec des &#171; 1 &#187; ou &#171; 0 &#187; pour le PBM. Il est important de noter que pour un m&#234;me format d'image peut correspondre des tailles en m&#233;moire diff&#233;rentes. Cela provient simplement d'une &#233;criture soit en mode binaire ou ASCII beaucoup plus lourde en espace. Le tableau qui suit r&#233;sume ces formats et leurs indicateurs.&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;Format&lt;/td&gt;&lt;td&gt;Indicateurs (ASCII,bin.)&lt;/td&gt;&lt;td&gt;Description&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;PBM&lt;/td&gt;&lt;td&gt;P4,P1&lt;/td&gt;&lt;td&gt;Monochome&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;PGM&lt;/td&gt;&lt;td&gt;P2,P5&lt;/td&gt;&lt;td&gt;Niveaux de gris&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;PPM&lt;/td&gt;&lt;td&gt;P3,P6&lt;/td&gt;&lt;td&gt;Couleur&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Une image PPM binaire pourrait alors avoir cette forme :&lt;/p&gt; &lt;div class=&quot;texteencadre-spip&quot;&gt;
&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;P6&lt;br /&gt; #Commentaire&lt;br /&gt; 320 292&lt;br /&gt; 255&lt;br /&gt; [...valeurs RGB...]&lt;br /&gt;&lt;/code&gt;&lt;/div&gt; &lt;/div&gt;
&lt;h2&gt;Programmation&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Pour acc&#233;der aux informations du fichier, il suffit d'utiliser une fonction &#171; fopen &#187; qui retournera un descripteur de fichier correspondant &#224; celui ouvert ou cr&#233;&#233;. M&#234;me si l'image peut &#234;tre repr&#233;sent&#233;e en valeurs binaires pour certains formats, il ne sera pas n&#233;cessaire d'ouvrir un fichier avec l'attribut binaire &#171; b &#187; ou de g&#233;rer la conversion en mode d&#233;cimal soit-m&#234;me.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Dans le programme pr&#233;sent&#233; ici, on ouvre un fichier PPM duquel on lit les informations pertinentes qu'on retransmet ensuite dans un second fichier PGM apr&#232;s application de la formule de niveaux de gris. Au lancement, des arguments sur le nom du fichier source et celui produit seront exig&#233;s.&lt;/p&gt; &lt;div class=&quot;texteencadre-spip&quot;&gt;
&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;int main (int argc, char **argv)&lt;br /&gt; {&lt;br /&gt; &lt;br /&gt; if (argc == 1)&lt;br /&gt; {&lt;br /&gt; printf (&quot;Arguments insuffisants\n&quot;);&lt;br /&gt; printf (&quot;nivgris [source] [destination]\n&quot;);&lt;br /&gt; return -1;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; fpr = fopen (argv[1], &quot;r&quot;);&lt;br /&gt; if (fpr == NULL)&lt;br /&gt; {&lt;br /&gt; printf (&quot;Impossible de lire le fichier\n&quot;);&lt;br /&gt; exit (-1);&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; fpw = fopen (argv[2], &quot;w&quot;);&lt;br /&gt; if (fpw == NULL)&lt;br /&gt; {&lt;br /&gt; printf (&quot;Impossible d'ouvrir le fichier en ecriture\n&quot;);&lt;br /&gt; exit (-1);&lt;br /&gt; }&lt;br /&gt;&lt;/code&gt;&lt;/div&gt; &lt;/div&gt;
&lt;p class=&quot;spip&quot;&gt;Un tableau de caract&#232;res servira de &#171; buffer &#187; pour comparer les informations d'ent&#234;te tir&#233;es du fichier en usant d'une fonction fgets. Nous nous assurerons d'abord d'avoir affaire au bon format de fichier en regardant le chiffre magique sur la premi&#232;re ligne. Si un commentaire est introduit sur la seconde ligne, il sera absorb&#233; par un fgets suppl&#233;mentaire. Pr&#233;cision ici qu'il est important d'avoir un fichier organis&#233; de la m&#234;me mani&#232;re qu'expliqu&#233;e plus haut car tous commentaires situ&#233;s ailleurs que sur la deuxi&#232;me ligne viendra d&#233;ranger l'ordre d'analyse. Bien s&#251;r, une version plus robuste de ce programme pourrait &#234;tre faite, mais rappelons qu'il doit servir d'abord de structure pour visualiser le r&#233;sultat des op&#233;rations de traitement.&lt;/p&gt; &lt;div class=&quot;texteencadre-spip&quot;&gt;
&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;fgets (info, 10, fpr);&lt;br /&gt; if (strncmp (info, &quot;P6&quot;, 2) != 0)&lt;br /&gt; {&lt;br /&gt; printf (&quot;Mauvais format de fichier\n&quot;);&lt;br /&gt; fclose (fpr);&lt;br /&gt; fclose (fpw);&lt;br /&gt; exit (-1);&lt;br /&gt; }&lt;br /&gt; fgets (info, 70, fpr);&lt;br /&gt; &lt;br /&gt; if ((strncmp (info, &quot;#&quot;, 1)) == 0)&lt;br /&gt; {&lt;br /&gt; fgets (info, 10, fpr);&lt;br /&gt; }&lt;br /&gt; sscanf (info, &quot;%d %d&quot;, &amp;largeur, &amp;hauteur);&lt;br /&gt; fgets (info, 10, fpr);&lt;br /&gt; sscanf (info, &quot;%d&quot;, &amp;valmax);&lt;br /&gt; if (valmax &amp;gt; 255)&lt;br /&gt; {&lt;br /&gt; printf (&quot;Valeur maximale trop eleve\n&quot;);&lt;br /&gt; fclose (fpr);&lt;br /&gt; fclose (fpw);&lt;br /&gt; exit (-1);&lt;br /&gt; }&lt;br /&gt;&lt;/code&gt;&lt;/div&gt; &lt;/div&gt;
&lt;p class=&quot;spip&quot;&gt;Pour lire l'ensemble des pixels de l'image, nous utiliserons les informations r&#233;cup&#233;r&#233;es dans l'ent&#234;te pour contr&#244;ler le d&#233;roulement d'une double boucle : une premi&#232;re s'ex&#233;cutera pour passer de ligne en ligne alors qu'une seconde avancera sur un m&#234;me ligne. Une seule boucle aurait pu &#233;galement &#234;tre employ&#233;e pour cette tache o&#249; le param&#232;tre de contr&#244;le serait le produit de la hauteur par la largeur.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Les valeurs RGB ainsi extraites seront utilis&#233;es pour le calcul du niveau de gris du pixel ensuite r&#233;&#233;crit dans le second fichier. Avant d'y placer ce pixel, il aura fallu d&#233;finir au pr&#233;lable des informations d'ent&#234;te pour l'image PGM tir&#233;es du fichier PPM &#224; la seule diff&#233;rence que &#171; P5 &#187; sera utilis&#233; plut&#244;t que &#171; P6 &#187;.&lt;/p&gt;
&lt;div class=&quot;texteencadre-spip&quot;&gt;
&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;fprintf (fpw, &quot;P5\n%d %d\n%d\n&quot;, largeur, hauteur, valmax);&lt;br /&gt; int x, y;&lt;br /&gt; unsigned char r, g, b, niv;&lt;br /&gt; &lt;br /&gt; for (y = 0; y &amp;lt; hauteur; y++)&lt;br /&gt; {&lt;br /&gt; for (x = 0; x &amp;lt; largeur; x++)&lt;br /&gt; {&lt;br /&gt; r = fgetc (fpr);&lt;br /&gt; g = fgetc (fpr);&lt;br /&gt; b = fgetc (fpr);&lt;br /&gt; niv = r * 0.299 + 0.587 * g + 0.114 * b;&lt;br /&gt; putc (niv, fpw);&lt;br /&gt; }&lt;br /&gt; }&lt;br /&gt;&lt;/code&gt;&lt;/div&gt; &lt;/div&gt;
&lt;p class=&quot;spip&quot;&gt;Les fichiers sont finalement ferm&#233;s et la fonction main retourne.&lt;/p&gt; &lt;div class=&quot;texteencadre-spip&quot;&gt;
&lt;div style='text-align: left;' class='spip_code' dir='ltr'&gt;&lt;code&gt;fclose (fpr);&lt;br /&gt; fclose (fpw);&lt;br /&gt; return 0;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt; &lt;/div&gt;
&lt;p class=&quot;spip&quot;&gt;Pour compiler, utilisez cette commande :&lt;/p&gt; &lt;div class=&quot;texteencadre-spip&quot;&gt;gcc -Wall niv_gris.c -o nivgris&lt;/div&gt;
&lt;p class=&quot;spip&quot;&gt;Une fois l'ex&#233;cutable cr&#233;&#233;, le lancement se fera ainsi :&lt;/p&gt; &lt;div class=&quot;texteencadre-spip&quot;&gt;./nivgris fichiersource.ppm fichiersortant.pgm&lt;/div&gt;
&lt;p class=&quot;spip&quot;&gt;Ce code peut certainement constituer une base efficace pour tester le r&#233;sultat de diff&#233;rents filtres d'images. Le passage d'une image de type RGB en niveaux de gris permettra l'application de m&#233;thodes de calcul de gradients pour l'extraction de contours. Cette prochaine &#233;tape sera d'ailleurs d&#233;taill&#233;e dans l'article suivant de cette s&#233;rie.&lt;/p&gt; &lt;div class='spip_document_250 spip_documents spip_documents_left' style='float:left;'&gt;
&lt;a href=&quot;http://aqra.ca/IMG/jpg/grenouille.jpg&quot; type=&quot;image/jpeg&quot; title='JPEG - 11.2 ko'&gt;&lt;img src='http://aqra.ca/IMG/cache-250x206/grenouille-250x206.jpg' width='250' height='206' alt=&quot;JPEG - 11.2 ko&quot; /&gt;&lt;/a&gt;
&lt;div class='spip_doc_titre' style='width:250px;'&gt;&lt;strong&gt;Image originale&lt;/strong&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class='spip_document_249 spip_documents spip_documents_left' style='float:left;'&gt;
&lt;a href=&quot;http://aqra.ca/IMG/jpg/resultat.jpg&quot; type=&quot;image/jpeg&quot; title='JPEG - 7.5 ko'&gt;&lt;img src='http://aqra.ca/IMG/cache-250x206/resultat-250x206.jpg' width='250' height='206' alt=&quot;JPEG - 7.5 ko&quot; /&gt;&lt;/a&gt;
&lt;div class='spip_doc_titre' style='width:250px;'&gt;&lt;strong&gt;R&#233;sultat&lt;/strong&gt;&lt;/div&gt;&lt;/div&gt; &lt;p class=&quot;spip&quot;&gt;&lt;/p&gt;&lt;/div&gt;
		
		</content:encoded>


		
		<enclosure url="http://aqra.ca/IMG/c/niv_gris.c" length="1641" type="text/x-csrc" />
		

	</item>



	<item>
		<title>Port parall&#232;le en C sous Linux</title>
		<link>http://aqra.ca/Port-parallele-en-C-sous-Linux</link>
		<guid isPermaLink="true">http://aqra.ca/Port-parallele-en-C-sous-Linux</guid>
		<dc:date>2004-06-12T23:03:54Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Pierre-Luc Bacon</dc:creator>

<category domain="http://aqra.ca/-Programmation-">Programmation</category>


		<description>Sommaire &lt;br /&gt;Le port parall&#232;le, commun &#224; tous les ordinateurs standards, se pr&#233;sente sous la forme d'un connecteur comptant 25 contacts. Ce connecteur, g&#233;n&#233;ralement d&#233;sign&#233; sous l'appellation &#171; sub-d &#187; ou DB25, a &#233;t&#233; originellement con&#231;u pour les imprimantes. Comme son nom l'indique, le port parall&#232;le envoie et re&#231;oit ses donn&#233;es en parall&#232;le, donc sur plusieurs broches &#224; la fois. Le tableau suivant dresse la liste des fonctions attribu&#233;es &#224; chacune de ces broches. &lt;br /&gt;Obtention de l'acc&#232;s &lt;br /&gt;Avant toutes manipulations (...)


-
&lt;a href="http://aqra.ca/-Programmation-" rel="directory"&gt;Programmation&lt;/a&gt;


		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;h2&gt;Sommaire&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Le port parall&#232;le, commun &#224; tous les ordinateurs standards, se pr&#233;sente sous la forme d'un connecteur comptant 25 contacts. Ce connecteur, g&#233;n&#233;ralement d&#233;sign&#233; sous l'appellation &#171; sub-d &#187; ou DB25, a &#233;t&#233; originellement con&#231;u pour les imprimantes. Comme son nom l'indique, le port parall&#232;le envoie et re&#231;oit ses donn&#233;es en parall&#232;le, donc sur plusieurs broches &#224; la fois. Le tableau suivant dresse la liste des fonctions attribu&#233;es &#224; chacune de ces broches.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;&lt;span class='spip_document_185 spip_documents spip_documents_center' &gt; &lt;img src='http://aqra.ca/IMG/cache-442x146/portpara-442x146.jpg' width='442' height='146' alt=&quot;&quot; /&gt;
&lt;/span&gt;&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;thead&gt;&lt;tr class='row_first'&gt;&lt;th scope='col'&gt;&lt;strong class=&quot;spip&quot;&gt;Numero&lt;/strong&gt;&lt;/th&gt;&lt;th scope='col'&gt;&lt;strong class=&quot;spip&quot;&gt;Nom&lt;/strong&gt;&lt;/th&gt;&lt;th scope='col'&gt;&lt;strong class=&quot;spip&quot;&gt;Fonction&lt;/strong&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Strobe&lt;/td&gt;&lt;td&gt;Impulsion &#224; z&#233;ro avant envoi&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;D0&lt;/td&gt;&lt;td&gt;Bit de donn&#233;e&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;D1&lt;/td&gt;&lt;td&gt;Bit de donn&#233;e&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;D2&lt;/td&gt;&lt;td&gt;Bit de donn&#233;e&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;D3&lt;/td&gt;&lt;td&gt;Bit de donn&#233;e&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;D4&lt;/td&gt;&lt;td&gt;Bit de donn&#233;e&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;D5&lt;/td&gt;&lt;td&gt;Bit de donn&#233;e&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;D6&lt;/td&gt;&lt;td&gt;Bit de donn&#233;e&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;9&lt;/td&gt;&lt;td&gt;D7&lt;/td&gt;&lt;td&gt;Bit de donn&#233;e&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;10&lt;/td&gt;&lt;td&gt;ACK&lt;/td&gt;&lt;td&gt;Bit d'&#233;tat&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;11&lt;/td&gt;&lt;td&gt;Busy&lt;/td&gt;&lt;td&gt;Bit d'&#233;tat&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;12&lt;/td&gt;&lt;td&gt;PE&lt;/td&gt;&lt;td&gt;Bit d'&#233;tat&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;13&lt;/td&gt;&lt;td&gt;Select&lt;/td&gt;&lt;td&gt;Bit d'&#233;tat&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;14&lt;/td&gt;&lt;td&gt;LF&lt;/td&gt;&lt;td&gt;Bit de contr&#244;le en sortie&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;15&lt;/td&gt;&lt;td&gt;ERR&lt;/td&gt;&lt;td&gt;Entr&#233;e&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;16&lt;/td&gt;&lt;td&gt;INIT&lt;/td&gt;&lt;td&gt;Bit de contr&#244;le en sortie&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;17&lt;/td&gt;&lt;td&gt;Select&lt;/td&gt;&lt;td&gt;Bit de contr&#244;le en sortie&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;18 a 25&lt;/td&gt;&lt;td&gt;Masse&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;Obtention de l'acc&#232;s&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Avant toutes manipulations sur le port, nous devons obtenir les droits d'acc&#232;s sur celui-ci. Pour ce faire nous utiliserons la fonction ioperm() d&#233;finie dans la librairie standard unistd.h. La d&#233;claration de cette fonction se pr&#233;sente ainsi :&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;&lt;strong class=&quot;spip&quot;&gt;int&lt;/strong&gt; &lt;strong class=&quot;spip&quot;&gt;ioperm(unsigned&lt;/strong&gt; &lt;strong class=&quot;spip&quot;&gt;long&lt;/strong&gt; from, &lt;strong class=&quot;spip&quot;&gt;unsigned long&lt;/strong&gt; num, &lt;strong class=&quot;spip&quot;&gt;int&lt;/strong&gt; turn_on&lt;strong class=&quot;spip&quot;&gt;) ;&lt;/strong&gt;&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;La valeur de retour de cette fonction est 0 en cas de r&#233;ussite et -1 pour un &#233;chec. Lorsque l'op&#233;ration &#233;choue, &lt;i class=&quot;spip&quot;&gt;errno&lt;/i&gt; est aussit&#244;t d&#233;fini.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Le premier param&#232;tre est celui indiquant le registre sur lequel nous demandons les permissions. Le port parall&#232;le dispose de trois registres :&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;strong class=&quot;spip&quot;&gt;0x378&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Registre de donn&#233;es (D0 a D7)&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;&lt;strong class=&quot;spip&quot;&gt;0x379&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Registre d'&#233;tat&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;strong class=&quot;spip&quot;&gt;0x37A&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Registre de contr&#244;le&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Le deuxi&#232;me &#233;l&#233;ment de &lt;i class=&quot;spip&quot;&gt;ioperm()&lt;/i&gt; repr&#233;sent&#233; par la variable &lt;i class=&quot;spip&quot;&gt;num&lt;/i&gt;, dans cet exemple, indique le nombres de ports cons&#233;cutifs devant &#234;tre ouverts &#224; la suite de &lt;i class=&quot;spip&quot;&gt;from&lt;/i&gt;. Quant &#224; l'expression &lt;i class=&quot;spip&quot;&gt;turn_on&lt;/i&gt;, elle contient une valeur enti&#232;re Bool&#233;enne sp&#233;cifiant simplement si les ports doivent &#234;tre ouverts (1) ou ferm&#233;s (0). Une attention devra donc &#234;tre port&#233;e de mani&#232;re &#224; &#233;viter d'omettre la fermeture d'un port dans un programme donn&#233;. Voici un exemple d'ouverture et de fermeture &#224; l'aide de la fonction ioperm() :&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='26' class='spip_cadre' dir='ltr'&gt;#include &amp;lt;unistd.h&amp;gt; #include &amp;lt;stdio.h&amp;gt; #define ADRESSEBASE 0x378 int main(void) { /*On ouvre le port, sinon perror()*/ if(ioperm(ADRESSEBASE, 1, 1) { perror(&quot;ioperm&quot;); exit(1); } /*On ferme le port*/ if(ioperm(ADRESSEBASE, 1, 0) { perror(&quot;ioperm&quot;); exit(1); } return(0); }&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt;
&lt;h2&gt;Op&#233;rations sur les ports&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;L'&#233;criture ou la lecture sur le port peut se faire par l'entremise des fonctions outb() et inb() respectivement. Ces deux fonctions prennent en charge des valeurs cod&#233;es sur un octet maximum, d'ou le &lt;i class=&quot;spip&quot;&gt;b&lt;/i&gt; signifiant &lt;i class=&quot;spip&quot;&gt;byte&lt;/i&gt;. Pour des valeurs sup&#233;rieurs, les fonctions outw() et in(w) issues de l'assembleur sont en mesure d'agir sur le premier port 8 bits (p) et sur le second (p+1). Dans cet article qui se consacre au port parall&#232;le de base, nous utiliserons les fonctions d'octet seulement. Mais sachez que les instructions de manipulations sur un mot (16 bits) pourraient vous &#234;tre utiles dans des applications o&#249; vous utiliserez des ports &#224; plus haut d&#233;bit comme le port ISA par exemple.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Les fonctions inb() et outb() exigent les arguments suivants :&lt;/p&gt; &lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='2' class='spip_cadre' dir='ltr'&gt;inb(port) outb(valeur, port)&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt;
&lt;h2&gt;Comment puis-je agir sur des broches sp&#233;cifiques ? &lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Comme nous l'avons vu plus haut, &#224; chaque broche est associ&#233; un bit donn&#233;. Donc &#233;crire sur une broche sp&#233;cifique revient simplement &#224; mettre le bit correspondant &#224; 1 ou 0.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Imaginons que l'on veuille mettre au niveau haut les broches 2, 3 et 7. Pour ce faire, nous allons d'abord nous reporter au tableau suivant qui met en correspondance bit et broche.&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;strong class=&quot;spip&quot;&gt;Broche&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;9&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;&lt;strong class=&quot;spip&quot;&gt;Bit&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;D0&lt;/td&gt;&lt;td&gt;D1&lt;/td&gt;&lt;td&gt;D2&lt;/td&gt;&lt;td&gt;D3&lt;/td&gt;&lt;td&gt;D4&lt;/td&gt;&lt;td&gt;D5&lt;/td&gt;&lt;td&gt;D6&lt;/td&gt;&lt;td&gt;D7&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;Dans notre exemple, l'octet qui sera &#233;crit aura ainsi la forme &lt;i class=&quot;spip&quot;&gt;00100011&lt;/i&gt;. Quelques notions de binaire suffisent ensuite pour effectuer la conversion vers la valeur d&#233;cimale :&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;1*2exp0 + 1*2exp1 +1*2exp5 = 35&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Ces quelques explications conduisent vers une version plus compl&#232;te du tableau pr&#233;c&#233;dent.&lt;/p&gt; &lt;table class=&quot;spip&quot;&gt;
&lt;tbody&gt;
&lt;tr class=&quot;row_even&quot;&gt;&lt;td&gt;&lt;strong class=&quot;spip&quot;&gt;Broche&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;9&lt;/td&gt;&lt;/tr&gt;
&lt;tr class=&quot;row_odd&quot;&gt;&lt;td&gt;&lt;strong class=&quot;spip&quot;&gt;Bit&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;D0&lt;/td&gt;&lt;td&gt;D1&lt;/td&gt;&lt;td&gt;D2&lt;/td&gt;&lt;td&gt;D3&lt;/td&gt;&lt;td&gt;D4&lt;/td&gt;&lt;td&gt;D5&lt;/td&gt;&lt;td&gt;D6&lt;/td&gt;&lt;td&gt;D7&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt; &lt;p class=&quot;spip&quot;&gt;|&lt;strong class=&quot;spip&quot;&gt;Valeur&lt;/strong&gt;|1|2|4|8|16|32|64|128|&lt;/p&gt; &lt;h2&gt;Programme r&#233;capitulatif&lt;/h2&gt;
&lt;form action=&quot;/&quot; method=&quot;get&quot;&gt;&lt;div&gt;&lt;textarea readonly='readonly' cols='40' rows='27' class='spip_cadre' dir='ltr'&gt;#include &amp;lt;stdio.h&amp;gt; #include &amp;lt;unistd.h&amp;gt; #include &amp;lt;asm/io.h&amp;gt; #define ADRESSEBASE 0x378 int main(void) { if(ioperm(ADRESSEBASE, 2, 1)) { perror(&quot;Erreur d'obtention des droits&quot;); exit(1); } outb(255, ADRESSEBASE); /*Toutes les broches a ON*/ sleep(2); /*Pendant 2 sec*/ printf(&quot;Valeur en entree: %d\n&quot;, inb(ADRESSEBASE+1)); if(ioperm(ADRESSEBASE, 2, 0)) { perror(&quot;Erreur de fermeture&quot;); exit(1); } }&lt;/textarea&gt;&lt;/div&gt;&lt;/form&gt;
&lt;h2&gt;Montage d'essais&lt;/h2&gt; &lt;p class=&quot;spip&quot;&gt;Vous pouvez visualiser le r&#233;sultat de vos exp&#233;rimentation rapidement en effectuant un simple montage &#224; base de DEL.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;&lt;span class='spip_document_188 spip_documents spip_documents_center' &gt; &lt;img src='http://aqra.ca/IMG/cache-383x314/portpar-383x314.jpg' width='383' height='314' alt=&quot;&quot; /&gt;
&lt;/span&gt;&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;Si vous comptez r&#233;aliser vos essais sur une plaques &#224; insertion, il serait fortement conseill&#233; de vous fabriquer un adapteur DB25 qui demeurera tr&#232;s utile en tout temps. Des circuits imprim&#233;s sont t&#233;l&#233;chargeables sur ce site &#224; la page de l'article concern&#233;.&lt;/p&gt; &lt;p class=&quot;spip&quot;&gt;&lt;i class=&quot;spip&quot;&gt;&lt;a href=&quot;http://aqra.ca/Adaptateurs-subd-pour-plaques-a&quot; class=&quot;spip_in&quot;&gt;Adapteur subd pour plaques &#224; insertion&lt;/a&gt;&lt;/i&gt;&lt;/p&gt; &lt;div class='spip_document_195 spip_documents spip_documents_center' &gt;
&lt;a href=&quot;http://aqra.ca/IMG/jpg/db25led2.jpg&quot; type=&quot;image/jpeg&quot; title='JPEG - 2.3 ko'&gt;&lt;img src='http://aqra.ca/IMG/cache-93x79/db25led2-93x79.jpg' width='93' height='79' alt=&quot;JPEG - 2.3 ko&quot; /&gt;&lt;/a&gt;
&lt;div class='spip_doc_titre' style='width:120px;'&gt;&lt;strong&gt;Visionneur d'&#233;tat &lt;/strong&gt;&lt;/div&gt;
&lt;div class='spip_doc_descriptif' style='width:120px;'&gt;Un outil plut&#244;t utile.&lt;/div&gt;&lt;/div&gt; &lt;p class=&quot;spip&quot;&gt;&lt;i class=&quot;spip&quot;&gt;Suivez les prochains articles o&#249; vous serons propos&#233;s plusieurs programmes, en cours d'&#233;criture, dont vous pourrez vous inspirer dans vos r&#233;alisations.&lt;/i&gt;&lt;/p&gt;&lt;/div&gt;
		&lt;div class='rss_ps'&gt;L'ex&#233;cution des programmes qui requi&#232;rent un acc&#232;s au port parall&#232;le doit se faire avec les privil&#232;ges de super-utilisateurs (root).&lt;/div&gt;
		</content:encoded>


		

	</item>





</channel>

</rss>
