futur ajout, une détection de mouvement.

Bonsoir, Pour résoudre le problème des parasites indésirables qui apparaissaient lors de la détection, la démarche est simple : Au plus petite sera la zone où il faut détecter la couleur du capteur, au moins je risque d'englober des pixels indésirables.
Pour cela je vais d'abord déterminer si il y a un mouvement et si mouvement il y a déterminer par le même procédé de THRESHOLD le rectangle d'activité qui délimitera une zone ou il faudra détecter la couleur. ca me permettra d'alléger le nombre de pixels à analyser, pour autant que la détection de mouvement ne soit pas trop gourmande par rapport à une détection directe de la couleur.

Voici un petit exemple de la détection de mouvement, le code source de l'application n'a pas beaucoup changé. Le principal ajout est l'utilisation de la méthode compare() de la classe BITMAPDATA.
La méthode compare me fournit un bitmapdata contenant la différence de chaque canal de couleur pour chaque pixel entre 2 images.

En résumé, si y a un mouvement, la différence entre 2 images successives, me donnera du noir là ou il n'y a pas de mouvement et du blanc là ou il y en aura apres avoir désaturé le résultat obtenu. Assez parlé, il sera plus simple d'imaginer ce que cela me permet en le testant.

Dans cette exemple, pas besoin de motif de couleur, il ne s'agit que de la détection de mouvment. Pour obtenir un meilleur résultat n'oubliez pas de jouer avec le blur et la saturation. saturation en dessous de 60% conseillé. blur au moins 50% conseillé.

NB: Attendez quelques secondes que l'écran de droite soit totalement noir pour faire un mouvement. Avant cela, la zone rectangulaire ne correspond pas au tracking du mouvement.

Denis P.

comments (0)
| More

Développement de la classe detectionCouleur.as

Bonjour,

Pour le moment, je me heurte à quelques problèmes. La webcam que j'utilise pour le développement est une webcam de 3.0 megapixels. La plupart des ordinateurs portables ont une webcam d'environ 1.3 megapixels. Je constate que lorsque j'utilise ma isight 1.3 megapixels les zones sombres se retrouve dans mon écart de couleur. Ma détection est donc faussée. De plus, mon écart de couleur englobe une bonne partie des couleurs vertes proches du motif, mais aussi les couleurs bleu. Je vais aussi faire un test avec un caméscope mis comme webcam pour voir comment réagit mon code avec une caméra supérieur à 3 mégapixels.

La technique employée pour l'écart de couleur actuellement ne se base que sur la méthode Threshold de la classe BITMAPDATA. le résultat n'est pas assez précis.

J'ai 2 pistes à exploiter :

La première continuer sur le principe de threshold mais arriver à l'aide d'un slider supplémentaire à pouvoir corriger "la balance des blancs de la caméra. ca permettra peut-être de pouvoir se recaler sur l'écart de couleur à détecter.

Pour effectuer une détection plus précise, il faut que j'analyse ou plutot que j'exploite la méthode GetPixels qui fera l'objet de mes futures tests. Parmi mes recherches, je suis tombé sur la nouvelle classe Vector qui s'avère vraiment plus rapide pour manipuler les données issues de chaque pixel.
http://www.mikechambers.com/blog/2009/10/13/case-study-actionscript-3-performance-optimization/.

Mais pour pouvoir l'utiliser, j'ai besoin de flash CS4.0 et surtout du lecteur flash 10 et non 9. les gains de performance indiqués dans l'article de Mike Chambers sont vraiment intéressants.

Voici pour le moment la version flash9 avec la méthode threshold :

detectionCouleur.as

package 
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.MovieClip;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.filters.BlurFilter;
	import flash.filters.ColorMatrixFilter;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.media.Camera;
	import flash.media.Video;
	import flash.text.TextField;
	import flash.text.TextFieldType;
	import flash.text.TextFormat;
	import flash.utils.Timer;
	import flash.events.TimerEvent;
	import flash.events.ActivityEvent;
	import flash.geom.Transform;
	import flash.geom.ColorTransform; 
	import fl.controls.Slider;
	import fl.events.SliderEvent;
        import fl.controls.SliderDirection;	
	import fl.controls.Label;
	/**
	 * ...
	 * @author Denis www.dipi-graphics.com
	 */
	public class detectionCouleur extends Sprite
	{
		//VARIABLE INIT
		var webcam:Camera;
		var vid:Video;
		var image:BitmapData;
		var imageB:Bitmap;
		var flip:Matrix = new Matrix();
 
		//isolant
		var threshold:uint =  0x00106010;
		var maskColor:uint = 0x00FFFFFF;
		var color:uint = 0xFF00FF00;
 
		//Pointeur
		var threshold1:uint =  0x0000ff00;
		var color1:uint = 0xFFFF0000;
		var maskColor1:uint = 0x0000FF00;
 
		//Constante
		var rect:Rectangle = new Rectangle(0,0,320,240);
		var pt:Point = new Point(0, 0);
		var rectPoint:Rectangle;
 
		//filtre
		//blur
		var flou:int = 5;
		var filter:BlurFilter = new BlurFilter(flou,flou,2);
 
		//saturation
		var s = 1;
		var rwgt:Number = .3086;
		var gwgt:Number = .6094;
		var bwgt:Number = .0820;
		var a:Number;
		var b:Number;
		var c:Number;
		var d:Number;
		var e:Number;
		var f:Number;
		var g:Number;
		var h:Number;
		var i:Number;
		var satMat:Array = new Array(a,b,c,0,0,d,e,f,0,0,g,h,i,0,0, 0, 0, 0, 1, 0);
		var saturate:ColorMatrixFilter = new ColorMatrixFilter(satMat);
 
		//OUTILS
		var rectangle:Shape = new Shape(); //zone rectangle de detection
		var blurSlider:Slider = new Slider();
		var blurLabel:Label = new Label()
		var blurText:TextField = new TextField();
		var saturationSlider:Slider = new Slider();
		var saturationLabel:Label = new Label();
		var saturationText:TextField = new TextField();
 
		//INITIALISATION
		public function detectionCouleur()
		{
			//Init Outils
			//const Slider Blur et Slider Saturation
			var format:TextFormat = new TextFormat();
                        format.font = "Arial";
                        format.color = 0x000000;
                        format.size = 10;
                        format.bold = true;
 
			//BLUR FILTER						          //SATURATION FILTER
                        blurText.defaultTextFormat = format;	        saturationText.defaultTextFormat = format;		
			blurText.text = "Blur Level";			        saturationText.text = "Saturation Level";
			blurText.selectable=false;				        saturationText.selectable=false;
			blurText.x = 360;						 saturationText.x = 360;
			blurText.y = 325;						        saturationText.y = 360;
			blurSlider.x = 360;						saturationSlider.x = 360;
			blurSlider.y = 345;						saturationSlider.y = 380;
			blurSlider.width = 200;					saturationSlider.width = 200;
			blurSlider.height = 20;					saturationSlider.height = 20;
			blurSlider.maximum = 100;				saturationSlider.maximum = 200;
			blurSlider.minimum = 0;					saturationSlider.minimum = 0;
			blurSlider.value = 50;					        saturationSlider.value = 50;
			blurLabel.text = "50%";					saturationLabel.text = "50%";
			blurLabel.x = 570;						saturationLabel.x = 570;
			blurLabel.y = 340;						saturationLabel.y = 375;
 
			addChild(blurText);
			addChild(blurSlider);
			addChild(blurLabel);
			addChild(saturationText);
			addChild(saturationSlider);
			addChild(saturationLabel);
 
			blurSlider.addEventListener(SliderEvent.CHANGE, blurHandler);
			saturationSlider.addEventListener(SliderEvent.CHANGE, saturationHandler);
 
			//matrice flip
			flip.translate( -320, 0 );
			flip.scale( -1, 1 );
 
			//matrice saturation
			a = rwgt + (1 - rwgt) * s;
			b = gwgt * (1 - s);
			c = bwgt * (1 - s);
			d = rwgt * (1 - s);
			e = gwgt + (1 - gwgt) * s;
			f = bwgt * (1 - s);
			g = rwgt * (1 - s);
			h = gwgt * (1 - s);
			i = bwgt + (1 - bwgt) * s;
			satMat = new Array(a, b, c, 0, 0, d, e, f, 0, 0, g, h, i, 0, 0, 0, 0, 0, 1, 0);
			saturate = new ColorMatrixFilter(satMat);
 
			//controle accès sécurisé à l'élément stage
			addEventListener(Event.ADDED_TO_STAGE,activation);
		}
		//ACTIVATION
		private function activation ( pEvt:Event ):void
		{
 
			var stageW = stage.stageWidth;
			var stageH = stage.stageHeight;
			webcam = Camera.getCamera();
			webcam.setMode( 320, 240, stage.frameRate );
			webcam.addEventListener(ActivityEvent.ACTIVITY, activityHandler);
			vid = new Video(320, 240);
			vid.attachCamera(webcam);
			vid.x=0;
			vid.y=80;
			addChild(vid);
			removeEventListener(Event.ADDED_TO_STAGE, activation);
		}
		private function activityHandler(evt:ActivityEvent):void 
		{
			image = new BitmapData(320, 240, false);
			imageB = new Bitmap(image);
			if (!webcam.muted) 
			{
 
				//affichage image capturée
				addChild(imageB);
				imageB.x = 320;
				imageB.y = 80;
				addChild(rectangle);
				//lancement du timer de capture
				var t:Timer = new Timer(50);
				t.addEventListener(TimerEvent.TIMER, timerHandler);
				t.start();
 
 
 
 
			}
			webcam.removeEventListener(ActivityEvent.ACTIVITY, activityHandler);
 
		}
		//TIMER 
		private function timerHandler(evt:TimerEvent)
		{
 
			image.draw(vid, flip);//dessine l'image capturée avec effet miroir
			image.applyFilter(image, rect, pt, filter);//filtre blur
			image.applyFilter(image,rect,pt,saturate);//filtre saturation
 
                        // ISOLANT
                        //tout ce qui n'est pas dans mon ecart de couleur devient Vert 
			image.threshold(image, rect, pt, ">", threshold , color, maskColor, true);   
 
                        // POINTEUR
                        //tout ce qui n'est pas vert devient rouge 
	                image.threshold(image, rect, pt, "!=", threshold1 , color1, maskColor1, true); 
 
			rectPoint = image.getColorBoundsRect(0x00FFFFFF, 0xFFFF0000, true);
			rectangle.graphics.clear();
			rectangle.graphics.lineStyle(2, 0x0000FF);
			rectangle.graphics.drawRect((rectPoint.x+320),(rectPoint.y+80),rectPoint.width,rectPoint.height);
 
		}
		//Slider EVENT
		private function blurHandler(event:SliderEvent):void 
		{
			blurLabel.text = event.value + "%";
			flou = event.value / 5;
			filter = new BlurFilter(flou, flou, 2);
		}
		private function saturationHandler(event:SliderEvent):void 
		{
			saturationLabel.text = event.value + "%";
			s = event.value / 50;
			a = rwgt + (1 - rwgt) * s;
			b = gwgt * (1 - s);
			c = bwgt * (1 - s);
			d = rwgt * (1 - s);
			e = gwgt + (1 - gwgt) * s;
			f = bwgt * (1 - s);
			g = rwgt * (1 - s);
			h = gwgt * (1 - s);
			i = bwgt + (1 - bwgt) * s;
			var satMat:Array = new Array(a, b, c, 0, 0, d, e, f, 0, 0, g, h, i, 0, 0, 0, 0, 0, 1, 0);
			saturate = new ColorMatrixFilter(satMat);
		}
	}
 
}

Démo :
imprimez le motif ou munissez vous d'un objet vert pour pouvoir faire fonctionner la démo.
(voir explication setup et fonctionnement)


Denis P.

comments (0)
| More

Détection couleur : interface pour setup

Bonjour,

J'ai construit une petite interface pour pouvoir configurer de manière simple la détection de couleur. Dans la vidéo ci dessous, j'explique et expérimente la détection dans 2 environnements différents au niveau de l'éclairage.

Envie d'essayer ?

Vous êtes invité à participer au test afin que je sache si cela fonctionne sur d'autres webcams.
Conditions d'utilisation optimale: background clair dans une piece éclairée par la lumière du jour. Eviter les objets sombres.

Denis P.

comments (0)
| More