Flash / Actionscript 3 Bitmap crop with feathered edges (blur edges)
I have been trying to figure out a good strategy to perform a bitmap crop using Actionscript3.
For example: I have a picture of a car and I want to crop out the car from the image alone and feather the edges so that they do not look jagged.
I am a flash noob and have only been using it for a couple of weeks. I've tried a couple of options and here is the last one that I have come up with it: I place red dots on stage that are draggable so that you can outline the object you want to crop and the dots are the bounds for a gradientFill that is used as the bitmap's mask. (I am using a radial gradient ... so the results are far from what I want, since the car is not an oval).
Here is a picture of the result.(ignore the random yellow dotted oval)
package code{
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.events.Event;
impor开发者_开发技巧t flash.events.MouseEvent;
//import flash.display.Graphics;
import fl.controls.Button;
import code.CropDot;
import flash.display.MovieClip;
import flash.display.GradientType;
import flash.display.SpreadMethod;
import flash.geom.Matrix;
import flash.display.Shape;
//import fl.controls.RadioButton;
public class BitmapEdit extends Sprite{
public var maskee:MovieClip;
public var bitmap:Bitmap;
public var dots:Sprite;
public var fill:MovieClip;
public var numDots:int;
public var circ:Shape = new Shape();
////////////////////
public var mat:Matrix=new Matrix();
public var circRad:Number=50;
public var offsetX:int;
public var offsetY:int;
public function BitmapEdit(bmp:Bitmap){
trace("bitmapedit");
//MASK Stuff
//--------------
bitmap = new Bitmap(bmp.bitmapData);
maskee = new MovieClip();
maskee.addChild(bitmap);
fill = new MovieClip();
this.addChild(maskee);
this.addChild(fill);
maskee.mask = fill;
maskee.cacheAsBitmap = true;
fill.cacheAsBitmap = true;
// DOTS DOTS DOTS
//---------------
dots = new Sprite();
numDots = 12;
offsetX = 90;
offsetY = 90;
cX = dot0.x+offsetX;
cY = dot0.y+offsetY;
rangeX = [cX,cX];
rangeY = [cY,cY];
for(var i:int=0;i<numDots;i++){
this['dot'+i.toString()].x += offsetX;
this['dot'+i.toString()].y += offsetY;
//this['dot'+i.toString()].name = 'dot'+i.toString();
dots.addChild(this['dot'+i.toString()])
cX+=dotX;
cY+=dotY;
if(dotX<=rangeX[0])
rangeX[0]=dotX;
else if(dotX>rangeX[1])
rangeX[1]=dotX;
if(dotY<=rangeY[0])
rangeY[0]=dotY;
else if(dotY>rangeY[1])
rangeY[1]=dotY;
}
cdot.x = cX;
cdot.y = cY;
this.addChild(dots);
fill.graphics.lineStyle(3,0,1.0,true);
this.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
public var cX:Number;
public var cY:Number;
public var dotX:Number;
public var dotY:Number;
public var prevdotX:Number;
public var prevdotY:Number;
public var rangeX:Array;
public var rangeY:Array;
protected function enterFrameHandler(e:Event){
//draw lines between dots
this.setChildIndex(fill,this.numChildren-2);
this.setChildIndex(dots,this.numChildren-1);
fill.graphics.clear();
//-Draw Fill
var fW = rangeX[1]-rangeX[0];
var fH = rangeY[1]-rangeY[0];
mat.createGradientBox(fW, fH, 0, cX-fW/2, cY-fH/2);
//fill.graphics.beginFill(0,1);
//fill.graphics.beginBitmapFill(bitmap.bitmapData);
//mat = new Matrix();
//fill.graphics.beginFill(0,1);
fill.graphics.beginGradientFill(GradientType.RADIAL,[0x000000, 0x000000], [1, 0], [123,255], mat, SpreadMethod.PAD, "rgb", 0);
fill.graphics.moveTo(dot0.x, dot0.y);
cX = dot0.x;
cY = dot0.y;
prevdotX = dot0.x;
prevdotY = dot0.y;
rangeX = [cX,cX];
rangeY = [cY,cY];
for(var i:int=1; i<numDots; i++){
dotX = this['dot'+i.toString()].x;
dotY = this['dot'+i.toString()].y;
fill.graphics.lineTo( dotX, dotY);
cX+=dotX;
cY+=dotY;
if(dotX<=rangeX[0])
rangeX[0]=dotX;
else if(dotX>rangeX[1])
rangeX[1]=dotX;
if(dotY<=rangeY[0])
rangeY[0]=dotY;
else if(dotY>rangeY[1])
rangeY[1]=dotY;
}
cX/=numDots;
cY/=numDots;
//trace("ctr:"+cX+","+cY);
cdot.x = cX;
cdot.y = cY;
fill.graphics.lineTo(dot0.x,dot0.y);
// */
//EndFill
fill.graphics.endFill();
}
function toRad(a:Number):Number {
return a*Math.PI/180;
}
}
}
Questions
1) How can I fade just the edges of this custom-shaped fill outlined by the red dots?
2) I want to save the image out to a file once it's cropped. What strategy would be better for doing this using a BitmapFill or a GradientFill as a Mask (If it's possible with both)?
3) I may be using this strategy to crop faces later on.. anyone know of any good face detection APIs for as3? (also edge detection APIs)
Thanks ahead everyone :)
1 ) what I've been using was creating a rectangle (for my needs) but a polygon should work... basically I create a graphic apply the blur filter and use it as mask. (instead of using the gradient)
2 ) have a look at the hype framework, there is one class in there that allow you to export images (tif,png) but there are other choices. Basically if you create a bitmap and use the draw function you can have a bitmap for exporting,
3 ) you should have a look at haar cascades in as3 here's one link with a lot of info for that, it's pretty slow in as3 for now, but who knows, maybe with the new molehills api this might change soon. http://web.elctech.com/2009/04/02/using-haar-cascades-and-opencv-in-as3/
精彩评论