[WebCam] ソラリゼーション Solarisation
ソラリゼーション Solarisation
こんな感じですかねー? ソラリゼーションって。
ステージクリックでちょっと変わります。
@author Aquioux(Yoshida, Akio)
/**
* Copyright Aquioux ( http://wonderfl.net/user/Aquioux )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/yvZ0
*/
package {
import flash.display.Sprite;
import net.hires.debug.Stats;
[SWF(width = "465", height = "465", frameRate = "30", backgroundColor = "#FFFFFF")]
/**
* ソラリゼーション Solarisation
* こんな感じですかねー? ソラリゼーションって。
* ステージクリックでちょっと変わります。
* @author Aquioux(Yoshida, Akio)
*/
public class Main extends Sprite {
public function Main():void {
Wonderfl.capture_delay(20);
// 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);
controller.view = view;
addChild(controller);
//addChild(new Stats());
}
}
}
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;
/**
* Model
* @author YOSHIDA, Akio (Aquioux)
*/
class Model extends EventDispatcher {
// ---------- パブリックプロパティ ----------
//
// View へ渡すデータ
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 solar_:Solarisation; // ソラリゼーション
private const ZERO_POINT:Point = EffectorUtils.ZERO_POINT;
private var isGray_:Boolean = true;
// ---------- パブリックメソッド ----------
//
/**
* コンストラクタ
* @param stage ステージ
* @param cw カメラ幅(省略時はステージ幅)
* @param ch カメラ高(省略時はステージ高)
*/
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;
// View へ渡すデータの生成
_data = new BitmapData(w, h, true, 0x00000000);
// 鏡像になるよう、Matrix で左右反転
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 のセットアップ
camera_.setMode(cameraWidth_, cameraHeight_, stage_.frameRate);
// video のセットアップ
video_ = new Video(cameraWidth_, cameraHeight_);
video_.attachCamera(camera_);
// カメラがアクティブになるまで待つ
camera_.addEventListener(ActivityEvent.ACTIVITY, activeHandler);
} else {
throw new Error("カメラがありません。");
}
// エフェクタ
smooth_ = new Smooth(); // 平滑化
smooth_.strength = 4;
grayscale_ = new GrayScale(); // グレイスケール
nega_ = new Negative(); // 反転
solar_ = new Solarisation(); // ソラリゼーション
}
/**
* isGray_ の切り替え
* Controller とのインターフェース
*/
public function notifyFromController():void {
isGray_ = !isGray_;
}
// ---------- ローカルメソッド ----------
//
// ACTIVITY イベントハンドラ
private function activeHandler(e:ActivityEvent):void {
camera_.removeEventListener(ActivityEvent.ACTIVITY, arguments.callee);
stage_.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
// ENTER_FRAME イベントハンドラ
private function enterFrameHandler(event:Event):void {
_data.draw(video_, matrix_);
smooth_.applyEffect(_data); // 平滑化
if (isGray_) grayscale_.applyEffect(_data); // グレイスケール
solar_.applyEffect(_data); // ソラリゼーション
if (!isGray_) nega_.applyEffect(_data); // 反転
dispatchEvent(new Event(Event.CHANGE));
}
}
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.events.Event;
/**
* View
* @author YOSHIDA, Akio (Aquioux)
*/
class View extends Bitmap {
// ---------- パブリックプロパティ ----------
//
// Model の参照
public function set model(value:Model):void { _model = value; }
private var _model:Model;
// ---------- パブリックメソッド ----------
//
/**
* コンストラクタ
* @param model Model
*/
public function View(model:Model) {
_model = model;
_model.addEventListener(Event.CHANGE, changeHandler);
}
// ---------- ローカルメソッド ----------
//
// Model から Event.CHANGE が発行されたときの処理
private function changeHandler(e:Event):void {
bitmapData = _model.data;
}
}
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
/**
* Controller
* @author YOSHIDA, Akio (Aquioux)
*/
class Controller extends Sprite {
// ---------- パブリックプロパティ ----------
//
// Model の参照
public function set model(value:Model):void { _model = value; }
private var _model:Model;
// View の参照
public function set view(value:View):void { _view = value; }
private var _view:View;
// ---------- パブリックメソッド ----------
//
/**
* コンストラクタ
* @param 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(MouseEvent.CLICK, clickHandler);
}
// イベントハンドラ
private function clickHandler(e:MouseEvent):void {
_model.notifyFromController();
}
}
import flash.display.BitmapData;
/**
* BitmapDataEffector 用 interface
* @author YOSHIDA, Akio (Aquioux)
*/
interface IEffector {
function applyEffect(value:BitmapData):BitmapData;
}
import flash.geom.Point;
/**
* bitmapDataEffector パッケージ内のクラスで共通に使う定数など
* @author YOSHIDA, Akio (Aquioux)
*/
class EffectorUtils {
// ---------- パブリックプロパティ ----------
//
// BitmapData が備える各種メソッドの destPoint 用
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;
}
// RGB チャンネルにおける濃度の各平均値を求める
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;
}
// RGB チャンネルにおける濃度の各平均値を求める
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.display.BlendMode;
import flash.geom.Point;
/**
* ソラリゼーション
* @author YOSHIDA, Akio (Aquioux)
*/
class Solarisation implements IEffector {
// ---------- ローカルプロパティ ----------
//
// バッファーとしての BitmapData
private var bufferBmd_:BitmapData;
// 反転エフェクタ
private var nega_:Negative = new Negative();
private const ZERO_POINT:Point = EffectorUtils.ZERO_POINT;
// ---------- パブリックメソッド ----------
//
/*
* 効果適用
* @param value 効果対象 BitmapData
*/
public function applyEffect(value:BitmapData):BitmapData {
if (!bufferBmd_) bufferBmd_ = value.clone();
bufferBmd_.copyPixels(value, value.rect, ZERO_POINT);
nega_.applyEffect(bufferBmd_);
value.draw(bufferBmd_, null, null, BlendMode.DIFFERENCE);
return value;
}
}
import flash.display.BitmapData;
import flash.filters.ColorMatrixFilter;
import flash.geom.Point;
/**
* ColorMatrixFilter による BitmapData のグレイスケール化(NTSC 系加重平均による)
* 参考:Foundation ActionScript 3.0 Image Effects(P106)
* http://www.amazon.co.jp/gp/product/1430218711?ie=UTF8&tag=laxcomplex-22
* @author YOSHIDA, Akio (Aquioux)
*/
class GrayScale implements IEffector {
// ---------- ローカルプロパティ ----------
//
private const MATRIX:Array = [
0.3, 0.59, 0.11, 0, 0,
0.3, 0.59, 0.11, 0, 0,
0.3, 0.59, 0.11, 0, 0,
0, 0, 0, 1, 0
];
private const FILTER:ColorMatrixFilter = new ColorMatrixFilter(MATRIX);
private const ZERO_POINT:Point = EffectorUtils.ZERO_POINT;
// ---------- パブリックメソッド ----------
//
/*
* 効果適用
* @param value 効果対象 BitmapData
*/
public function applyEffect(value:BitmapData):BitmapData {
value.applyFilter(value, value.rect, ZERO_POINT, FILTER);
return value;
}
}
import flash.display.BitmapData;
import flash.filters.BitmapFilterQuality;
import flash.filters.BlurFilter;
import flash.geom.Point;
/**
* BlurFilter による平滑化
* @author YOSHIDA, Akio (Aquioux)
*/
class Smooth implements IEffector {
// ---------- パブリックプロパティ ----------
//
/*
* ぼかしの強さ
* @param value 数値
*/
public function set strength(value:Number):void {
filter_.blurX = filter_.blurY = value;
}
/*
* ぼかしの質
* @param 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);
}
/*
* 効果適用
* @param value 効果対象 BitmapData
*/
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;
/**
* ConvolutionFilter による BitmapData の色反転
* 参考:http://www40.atwiki.jp/spellbound/pages/231.html
* @author YOSHIDA, Akio (Aquioux)
*/
class Negative implements IEffector {
// ---------- ローカルプロパティ ----------
//
private const FILTER:ConvolutionFilter = new ConvolutionFilter(1, 1, [ -1], 1, 255);
private const ZERO_POINT:Point = EffectorUtils.ZERO_POINT;
// ---------- パブリックメソッド ----------
//
/*
* 効果適用
* @param value 効果対象 BitmapData
*/
public function applyEffect(value:BitmapData):BitmapData {
value.applyFilter(value, value.rect, ZERO_POINT, FILTER);
return value;
}
}