James SharpQUTforked from: [WebCam] Manic Monday
Forked from: [WebCam] Manic Monday
説明:http://aquioux.blog48.fc2.com/blog-entry-710.html
@author Aquioux(Yoshida, Akio)
&author james sharp
/**
* Copyright jamessharp89 ( http://wonderfl.net/user/jamessharp89 )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/yPLD
*/
// forked from Aquioux's [WebCam] Manic Monday
package {
import flash.display.Sprite;
//import net.hires.debug.Stats;
[SWF(width = "465", height = "465", frameRate = "30", backgroundColor = "#FF0000")]
/**
* Forked from: [WebCam] Manic Monday
* http://aquioux.blog48.fc2.com/blog-entry-710.html
* @author james sharp
*/
//modify lines: 101,129,154,219,265-8
public class Main extends Sprite {
public function Main():void {
//Wonderfl.capture_delay(30);
// model
try {
var model:Model = new Model(stage);
} catch (err:Error) {
trace(err.message);
return;
}
// view
var view:View = new View(model);
addChild(view);
// controller
var controller:Controller = new Controller(model);
addChild(controller);
}
}
}
import flash.display.BitmapData;
import flash.display.Stage;
import flash.events.ActivityEvent;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.media.Camera;
import flash.media.Video;
class Model extends EventDispatcher {
public function get data():BitmapData { return _data; }
private var _data:BitmapData;
private var stage_:Stage;
private var cameraWidth_:uint;
private var cameraHeight_:uint;
private var camera_:Camera;
private var video_:Video;
private var matrix_:Matrix;
private var smooth_:Smooth;
private var grayscale_:GrayScale;
private var nega_:Negative;
private var binarize_:Binarize;
private var divider_:SubDivider;
private var gray_:BitmapData;
private var rect_:Rectangle;
private const ZERO_POINT:Point = EffectorUtils.ZERO_POINT;
private var isNegative_:Boolean = false;
public function Model(stage:Stage, cw:uint = 0, ch:uint = 0) {
stage_ = stage;
var w:uint = stage_.stageWidth;
var h:uint = stage_.stageHeight;
cameraWidth_ = (cw == 0) ? w : cw;
cameraHeight_ = (ch == 0) ? h : ch;
_data = new BitmapData(w, h, true, 0x00000000);
gray_ = new BitmapData(w, h, false, 0x000000);
rect_ = _data.rect;
var tx:uint = (w - cameraWidth_) / 2 + cameraWidth_;
var ty:uint = (h - cameraHeight_) / 2;
matrix_ = new Matrix( -1, 0, 0, 1, tx, ty);
camera_ = Camera.getCamera();
if (camera_) {
camera_.setMode(cameraWidth_, cameraHeight_, stage_.frameRate);
video_ = new Video(cameraWidth_, cameraHeight_);
video_.attachCamera(camera_);
camera_.addEventListener(ActivityEvent.ACTIVITY, activeHandler);
} else {
throw new Error("an error has occured! Is your webcam connected?");
}
smooth_ = new Smooth();
smooth_.strength = 0; //change strength for more solid shaped. eg + 50 is very solid. originally 4
grayscale_ = new GrayScale();
nega_ = new Negative();
binarize_ = new Binarize();
binarize_.auto = true;
divider_ = new SubDivider();
}
public function notifyFromController():void {
isNegative_ = !isNegative_;
}
private function activeHandler(e:ActivityEvent):void {
camera_.removeEventListener(ActivityEvent.ACTIVITY, arguments.callee);
stage_.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
private function enterFrameHandler(event:Event):void {
_data.draw(video_, matrix_);
smooth_.applyEffect(_data);
grayscale_.applyEffect(_data);
gray_.copyPixels(_data, rect_, ZERO_POINT);
if (isNegative_) nega_.applyEffect(gray_);
binarize_.applyEffect(gray_);
_data.fillRect(rect_, 0x00000000);
//size of smalest block. change from around 5-25 where 2 small blocks, 20 solid. originally 10
//has an effect on the colours
divider_.applyEffect(rect_, gray_, _data, 8, 8, binarize_.threshold);
dispatchEvent(new Event(Event.CHANGE));
}
}
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.events.Event;
import flash.filters.DropShadowFilter;
import flash.geom.Point;
import flash.geom.Rectangle;
class View extends Bitmap {
public function set model(value:Model):void { _model = value; }
private var _model:Model;
private var filter:DropShadowFilter;
public function View(model:Model) {
_model = model;
_model.addEventListener(Event.CHANGE, changeHandler);
//play around with this (size, angle, colour, alpha, xblur, yblur)
filter = new DropShadowFilter(5, 45, 0x666666, 1, 8, 8);//changes the colour of the shadow around the blocks
filters = [filter];
}
private function changeHandler(e:Event):void {
bitmapData = _model.data;
}
}
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
class Controller extends Sprite {
public function set model(value:Model):void { _model = value; }
private var _model:Model;
public function Controller(model:Model) {
_model = model;
addEventListener(Event.ADDED_TO_STAGE, addToStageHandler);
}
private function addToStageHandler(e:Event):void {
removeEventListener(Event.ADDED_TO_STAGE, arguments.callee);
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
}
private function keyDownHandler(e:KeyboardEvent):void {
if (e.keyCode == 82) _model.notifyFromController(); // "r" invert the light
}
}
import flash.display.BitmapData;
import flash.display.Graphics;
import flash.geom.Rectangle;
import frocessing.color.ColorHSV;
class SubDivider {
//create the rectangle
private var nextRect_:Rectangle = new Rectangle();
private var drawRect_:Rectangle = new Rectangle();
private const GET_BRIGHTNESS:Function = EffectorUtils.getSumOfBrightness1;
public var hsv_:ColorHSV = new ColorHSV();
public function SubDivider() {
}
//here we create affects to the rectagles size etc
public function applyEffect(rect:Rectangle, gray:BitmapData, canvas:BitmapData, divideThreshold:uint, minSize:uint, drawThreshold:uint, callInner:Boolean = false):void {
if (!callInner) hsv_.h = 0;
var isDivide:Boolean = rect.width > minSize && rect.height > minSize;
var numOfPixel:uint = rect.width * rect.height;
var hist:Vector.<Vector.<Number>> = gray.histogram(rect);
if (isDivide) {
var deviation:Number = getStandardDeviation(hist[0], numOfPixel);
if (deviation > divideThreshold) {
//size of shapes..change for great results
var nextWidth1:uint = rect.width /2; //between 1.5 and 5
var nextHeight1:uint = rect.height /2;//between 1.5 and 5
var nextWidth2:uint = (rect.width - nextWidth1) * 1;//*1.2;
var nextHeight2:uint = (rect.height - nextHeight1) * 1;//*1.2;
var left:Number = rect.x;
var top:Number = rect.y;
var center:Number = left + nextWidth1;
var middle:Number = top + nextHeight1;
var xs:Vector.<uint> = Vector.<uint>([left, center, left, center]);
var ys:Vector.<uint> = Vector.<uint>([top, top, middle, middle]);
var ws:Vector.<uint> = Vector.<uint>([nextWidth1, nextWidth2, nextWidth1, nextWidth2]);
var hs:Vector.<uint> = Vector.<uint>([nextHeight1, nextHeight1, nextHeight2, nextHeight2]);
for (var i:int = 0; i < 4; i++) {
nextRect_.x = xs[i];
nextRect_.y = ys[i];
nextRect_.width = ws[i];
nextRect_.height = hs[i];
applyEffect(nextRect_, gray, canvas, divideThreshold, minSize, drawThreshold, true);
}
} else {
isDivide = false;
}
}
if (!isDivide) draw(rect, hist[0], numOfPixel, canvas, drawThreshold);
}
private function getStandardDeviation(hist:Vector.<Number>, numOfPixel:uint):Number {
var average:Number = hist[255] * 255 / numOfPixel;
var diff:Number = 0;
var sum:uint = 0;
diff = -average;
sum += diff * diff * hist[0];
diff = 255 - average;
sum += diff * diff * hist[255];
return Math.sqrt(sum / numOfPixel);
}
private function draw(rect:Rectangle, hist:Vector.<Number>, numOfPixel:uint, canvas:BitmapData, threshold:uint):void {
var sum:uint = GET_BRIGHTNESS(hist);
var brightness:uint = sum / numOfPixel;
if (brightness < threshold) {
drawRect_.x = rect.x + 1;
drawRect_.y = rect.y + 1;
drawRect_.width = rect.width - 2; //distance between blocks, originally 2
drawRect_.height = rect.height - 2;
canvas.fillRect(drawRect_, hsv_.value32);
hsv_.h += 0.3; //speed and rate of block changing colour
}
}
}
import flash.display.BitmapData;
interface IEffector {
function applyEffect(value:BitmapData):BitmapData;
}
import flash.geom.Point;
class EffectorUtils {
static public const ZERO_POINT:Point = new Point(0, 0);
static public function getAverageOfBrightness1(hist:Vector.<Number>):uint {
var sum:uint = 0;
var numOfPixel:uint = 0;
for (var i:int = 0; i < 256; i++) {
sum += i * hist[i];
numOfPixel += hist[i];
}
return sum / numOfPixel >> 0;
}
static public function getAverageOfBrightness3(hist:Vector.<Vector.<Number>>):Vector.<uint> {
var rSum:uint = 0;
var gSum:uint = 0;
var bSum:uint = 0;
var numOfPixel:uint = 0;
for (var i:int = 0; i < 256; i++) {
rSum += i * hist[0][i];
gSum += i * hist[1][i];
bSum += i * hist[2][i];
numOfPixel += hist[0];
}
return Vector.<uint>([rSum / numOfPixel >> 0, gSum / numOfPixel >> 0, bSum / numOfPixel >> 0]);
}
static public function getSumOfBrightness1(hist:Vector.<Number>):uint {
var sum:uint = 0;
for (var i:int = 0; i < 256; i++) {
sum += i * hist[i];
}
return sum;
}
static public function getSumOfBrightness3(hist:Vector.<Vector.<Number>>):Vector.<uint> {
var rSum:uint = 0;
var gSum:uint = 0;
var bSum:uint = 0;
for (var i:int = 0; i < 256; i++) {
rSum += i * hist[0][i];
gSum += i * hist[1][i];
bSum += i * hist[2][i];
}
return Vector.<uint>([rSum, gSum, bSum]);
}
}
import flash.display.BitmapData;
import flash.filters.BitmapFilterQuality;
import flash.filters.BlurFilter;
import flash.geom.Point;
class Smooth implements IEffector {
public function set strength(value:Number):void {
filter_.blurX = filter_.blurY = value;
}
public function set quality(value:int):void {
filter_.quality = value;
}
private var filter_:BlurFilter;
private const ZERO_POINT:Point = EffectorUtils.ZERO_POINT;
public function Smooth() {
filter_ = new BlurFilter(2, 2, BitmapFilterQuality.MEDIUM);
}
public function applyEffect(value:BitmapData):BitmapData {
value.applyFilter(value, value.rect, ZERO_POINT, filter_);
return value;
}
}
import flash.display.BitmapData;
import flash.filters.ColorMatrixFilter;
import flash.geom.Point;
class GrayScale implements IEffector {
//RGB COLOURS
private const R:Number = .8;//
private const G:Number = .1;//
private const B:Number = .8;//
private const MATRIX:Array = [
R, G, B, 0, 0,
R, G, B, 0, 0,
R, G, B, 0, 0,
0, 0, 0, 1, 0
];
private const FILTER:ColorMatrixFilter = new ColorMatrixFilter(MATRIX);
private const ZERO_POINT:Point = EffectorUtils.ZERO_POINT;
public function applyEffect(value:BitmapData):BitmapData {
value.applyFilter(value, value.rect, ZERO_POINT, FILTER);
return value;
}
}
import flash.display.BitmapData;
import flash.filters.ConvolutionFilter;
import flash.geom.Point;
class Negative implements IEffector {
private const FILTER:ConvolutionFilter = new ConvolutionFilter(1, 1, [ -1], 1, 255);
private const ZERO_POINT:Point = EffectorUtils.ZERO_POINT;
public function applyEffect(value:BitmapData):BitmapData {
value.applyFilter(value, value.rect, ZERO_POINT, FILTER);
return value;
}
}
import flash.display.BitmapData;
import flash.geom.Point;
import flash.geom.Rectangle;
class Binarize implements IEffector {
public function get threshold():int { return _threshold; }
public function set threshold(value:int):void {
if (value < 0) value = 0;
if (value > 255) value = 255;
_threshold = value;
}
private var _threshold:int = 127; //:0 ~ 255
public function get auto():Boolean { return _auto; }
public function set auto(value:Boolean):void { _auto = value; }
private var _auto:Boolean = false;
private const ZERO_POINT:Point = EffectorUtils.ZERO_POINT;
public function applyEffect(value:BitmapData):BitmapData {
var bufferBmd:BitmapData = new BitmapData(value.width, value.height);
var rect:Rectangle = bufferBmd.rect;
bufferBmd = value.clone();
if (_auto) {
var hist:Vector.<Vector.<Number>> = value.histogram();
var numOfPixel:uint = rect.width * rect.height;
_threshold = calcThresholdRough(hist[2], numOfPixel);
}
value.fillRect(rect, 0x3299CC);
value.threshold(bufferBmd, rect, ZERO_POINT, ">", _threshold, 0xFFFFFFFF, 0x000000FF, false);
return value;
}
private function calcThresholdRough(hist:Vector.<Number>, numOfPixel:uint):uint {
var total:uint;
for (var i:int = 0; i < 256; i++) {
total += hist[i] * i;
}
return total / numOfPixel >> 0;
}
private function calcThresholdStrict(hist:Vector.<Number>, numOfPixel:uint):uint {
var maxSeparability:Number = 0;
var maxDegree:uint = 0;
for (var i:int = 1; i < 255; i++) {
//create var for below fucntion (calcSeparability)
var Separability:Number = calcSeparability(i, hist, numOfPixel);
if (Separability > maxSeparability) {
maxSeparability = Separability;
maxDegree = i;
}
}
return maxDegree;
}
//makes sure constant (a threshold for max and min number to never leave blank amount)
private function calcSeparability(threshold:uint, hist:Vector.<Number>, numOfPixel:uint):Number {
var i:uint;
var num1:uint = 0, num2:uint = 0;
var con1:Number = 0, con2:Number = 0;
var con:Number = 0;
var dis1:Number, dis2:Number;
var within:Number = 0;
var between:Number = 0;
for (i = 0; i < threshold; i++) {
num1 += hist[i];
con1 += i * hist[i];
}
for (i = threshold; i < 256; i++) {
num2 += hist[i];
con2 += i * hist[i];
}
con = (con1 + con2) / numOfPixel;
con1 /= num1;
con2 /= num2;
if (num1 == 0 || num2 == 0) return 0;
for (i = 0; i < threshold; i++) {
dis1 = i - con1;
within += dis1 * dis1 * hist[i];
}
for (i = threshold; i < 256; i++) {
dis2 = i - con2;
within += dis2 * dis2 * hist[i];
}
within /= numOfPixel;
for (i = 0; i < threshold; i++) {
dis1 = con - con1;
between += dis1 * dis1 * hist[i];
}
for (i = threshold; i < 256; i++) {
dis2 = con - con2;
between += dis2 * dis2 * hist[i];
}
between /= numOfPixel;
return between / within;
}
}