Aplicar filtro de desenfoque a áreas de forma libre

Tengo que construir una aplicación flash para el retoque de arrugas simple. El usuario debería poder cargar una foto de retrato, seleccionar las áreas arrugadas y luego se aplicará un filtro de desenfoque a las partes seleccionadas. Mi pregunta es: ¿es posible aplicar el filtro a un área de forma libre? Sé que sería fácil hacer la selección rectangular, pero eso no sería muy útil para marcar realmente las áreas correctas. Idealmente, el usuario debe obtener algún tipo de cepillo redondo para marcar las áreas, presione "OK" y luego se aplicará el filtro. ¿Hay alguna manera de hacer esto? ¿Y tal vez tenga algunas recomendaciones adicionales sobre cómo abordar esta tarea? Tengo muy poca experiencia en la manipulación de datos de mapa de bits con ActionScript.

¡Cualquier ayuda es apreciada! Muchas gracias de antemano :-)

Ejemplo de cómo debería verse...

preguntado el 03 de mayo de 12 a las 11:05

1 Respuestas

El algoritmo es el siguiente:

  1. crear un BitmapData de forma de selección usando BitmapData.draw() (que sea A)
  2. corte una pieza rectangular de la imagen original que esté cubierta por el área de selección, agregue algunos márgenes para el área borrosa usando Bitmapdata.copyPixels() (que sea B).
  3. eliminar todos los píxeles de B, que no están cubiertos por la forma A con BitmapData.threshold() utilizando A como mapa de bits de origen.
  4. difuminar la imagen resultante
  5. copie los píxeles borrosos de nuevo a la imagen de destino usando Bitmapdata.copyPixels()

Aquí hay un ejemplo completo y funcional.
De todos modos, escribí el código mientras buscaba la solución.
Espero que lo encuentre útil.

package
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Loader;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.filters.BlurFilter;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.net.URLRequest;
    import flash.system.LoaderContext;

    [SWF(width="800", height="600",backgroundColor="#FFFFFF")]    
    public class TestBlur extends Sprite
    {
        private const loader:Loader = new Loader();

        public function TestBlur()
        {
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;

            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete);
            loader.load(new URLRequest("http://i.stack.imgur.com/u3iEv.png"), new LoaderContext(true));
        }

        protected function onLoadComplete(event:Event):void
        {
            trace(event);
            var bmp:Bitmap = loader.content as Bitmap;
            addChild(bmp);

            // create some test selection area
            var selection:Shape = new Shape();
            selection.graphics.lineStyle(30, 0xFF0000, .5);
            selection.graphics.curveTo(75, -50, 200, 10);
            selection.x = 40;
            selection.y = 60;
            addChild(selection);

            // create a duplicate of the original image
            var target:BitmapData = bmp.bitmapData.clone();
            var targetBmp:Bitmap = new Bitmap(target);
            targetBmp.x = bmp.x + bmp.width;
            addChild(targetBmp);

            //
            // *** main work starts here ***
            // by now we have selection shape and a bitmap to blur

            const destPoint:Point = new Point();
            const drawMatrix:Matrix = new Matrix();
            const blurMargin:uint = 10;
            const blur:BlurFilter = new BlurFilter(2, 2, 3);
            var rect:Rectangle;

            // 0: prepare an image of selection area
            // we'll need it at step 3
            rect = selection.getBounds(selection);
            rect.x -= blurMargin;
            rect.y -= blurMargin;
            rect.width += blurMargin*2;
            rect.height += blurMargin*2;            
            var selectionImage:BitmapData = new BitmapData(rect.width, rect.height, true, 0);
            drawMatrix.identity();
            drawMatrix.translate(-rect.x, -rect.y);
            selectionImage.draw(selection, drawMatrix);

                    // just some testing
                    var test0:Bitmap = new Bitmap(selectionImage.clone());
                    test0.y = bmp.y + bmp.height;
                    addChild(test0);

            // 1: cut a rectangular piece of original image that is covered by selection area
            rect = selection.getBounds(selection.parent);
            rect.x -= blurMargin;
            rect.y -= blurMargin;
            rect.width += blurMargin*2;
            rect.height += blurMargin*2;
            var area:BitmapData = new BitmapData(rect.width, rect.height, true, 0);
            area.copyPixels(bmp.bitmapData, rect, destPoint);

                    // just some testing
                    var test1:Bitmap = new Bitmap(area.clone());
                    test1.y = bmp.y + bmp.height;
                    test1.x = test0.x + test0.width;
                    addChild(test1);

            // 2: remove all pixels that are not covered by selection
            area.threshold(selectionImage, area.rect, destPoint, "==", 0, 0, 0xFF000000);

                    // just some testing
                    var test2:Bitmap = new Bitmap(area.clone());
                    test2.y = test0.y + test0.height;
                    test2.x = test0.x;
                    addChild(test2);

            // 3: blur copied area
            area.applyFilter(area, area.rect, destPoint, blur);

                    // just some testing
                    var test3:Bitmap = new Bitmap(area.clone());
                    test3.y = test0.y + test0.height;
                    test3.x = test2.x + test2.width;
                    addChild(test3);

            // 4: copy blurred pixels back to target image
            destPoint.x = rect.x;
            destPoint.y = rect.y;
            target.copyPixels(area, area.rect, destPoint);
        }        
    }
}

contestado el 05 de mayo de 12 a las 03:05

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.