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.