カメラ映像をテキストで再描画
元ネタは、2010年のYouTubeのエイプリルフールネタです。
http://youtubejpblog.blogspot.com/2010/03/textp-youtube.html
動画を全てテキストで処理してお届けしますよ(そうするとエコでしょ?)みたいなヤツだったのですが、
flashでリアルタイム処理出来ないかと思い至ったので、やってみました。
ソースを見ると気づくと思いますが、元ネタは、カメラ映像のモザイク処理です。
rsakaneさんのwikiに掲載のコードを使用しています。
http://www40.atwiki.jp/spellbound/?cmd=word&word=%E3%83%A2%E3%82%B6%E3%82%A4%E3%82%AF&type=normal&page=%E7%94%BB%E5%83%8F%E3%81%AB%E3%83%A2%E3%82%B6%E3%82%A4%E3%82%AF%E3%82%92%E3%81%8B%E3%81%91%E3%82%8B%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E6%9B%B8%E3%81%84%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86
なお、ソースは思いつくままに書いたのでかなりこってりしたコードです。
_blockSizeで、モザイク処理するピクセルサイズ(=フォントのサイズ)を変更出来ます。
_pixelOffsetは、テキストフィールドの位置とフォントの位置を合わせるために使用しているオフセット値です。
/**
* Copyright kitsuneotoko ( http://wonderfl.net/user/kitsuneotoko )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/ApfL
*/
/*
元ネタは、2010年のYouTubeのエイプリルフールネタです。
http://youtubejpblog.blogspot.com/2010/03/textp-youtube.html
動画を全てテキストで処理してお届けしますよ(そうするとエコでしょ?)みたいなヤツだったのですが、
flashでリアルタイム処理出来ないかと思い至ったので、やってみました。
ソースを見ると気づくと思いますが、元ネタは、カメラ映像のモザイク処理です。
rsakaneさんのwikiに掲載のコードを使用しています。
http://www40.atwiki.jp/spellbound/?cmd=word&word=%E3%83%A2%E3%82%B6%E3%82%A4%E3%82%AF&type=normal&page=%E7%94%BB%E5%83%8F%E3%81%AB%E3%83%A2%E3%82%B6%E3%82%A4%E3%82%AF%E3%82%92%E3%81%8B%E3%81%91%E3%82%8B%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E6%9B%B8%E3%81%84%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86
なお、ソースは思いつくままに書いたのでかなりこってりしたコードです。
_blockSizeで、モザイク処理するピクセルサイズ(=フォントのサイズ)を変更出来ます。
_pixelOffsetは、テキストフィールドの位置とフォントの位置を合わせるために使用しているオフセット値です。
*/
package {
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.media.Camera;
import flash.media.Video;
import flash.text.*;
import frocessing.color.ColorRGB;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
public class CameraMain extends Sprite {
private var _blockSize:uint = 10;// テキストでモザイク処理を行う際のブロックサイズ
private var _pixelOffset:uint = 2;//テキストフィールドのオフセット値
private var _camera:Camera;
private var _cameraWidth:Number;
private var _cameraHeight:Number;
private var _video:Video;
private var _bitmapData:BitmapData;
private var _textFields:Sprite;
private var _textFieldArray:Array;
private var _kanaList:Array = ['ァ', 'ア', 'ィ', 'イ', 'ゥ', 'ウ', 'ェ', 'エ', 'ォ', 'オ', 'カ', 'ガ', 'キ', 'ギ', 'ク', 'グ', 'ケ', 'ゲ', 'コ', 'ゴ', 'サ', 'ザ', 'シ', 'ジ', 'ス', 'ズ', 'セ', 'ゼ', 'ソ', 'ゾ', 'タ', 'ダ', 'チ', 'ヂ', 'ッ', 'ツ', 'ヅ', 'テ', 'デ', 'ト', 'ド', 'ナ', 'ニ', 'ヌ', 'ネ', 'ノ', 'ハ', 'バ', 'パ', 'ヒ', 'ビ', 'ピ', 'フ', 'ブ', 'プ', 'ヘ', 'ベ', 'ペ', 'ホ', 'ボ', 'ポ', 'マ', 'ミ', 'ム', 'メ', 'モ', 'ャ', 'ヤ', 'ュ', 'ユ', 'ョ', 'ヨ', 'ラ', 'リ', 'ル', 'レ', 'ロ', 'ヮ', 'ワ', 'ヰ', 'ヱ', 'ヲ', 'ン', 'ヴ', 'ヵ', 'ヶ'];
//private var _byteArray:ByteArray;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
public function CameraMain() {
init();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
private function init():void{
var bg:Sprite = new Sprite;
bg.graphics.beginFill(0x000000);
bg.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
bg.graphics.endFill();
addChild(bg);
_camera = Camera.getCamera();
_cameraWidth = stage.stageWidth;
_cameraHeight = stage.stageWidth/_camera.width *_camera.height;
_video = new Video(_cameraWidth, _cameraHeight);
_video.attachCamera(_camera);
_bitmapData = new BitmapData(_cameraWidth, _cameraHeight);
//addChild(new Bitmap(_bitmapData));
addChild(_textFields = new Sprite);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// _cameraWidth, _cameraHeight, _blockSizeを元にテキストフィールドを作成し
// 参照を配列に格納
var xCount:Number = _cameraWidth / _blockSize <<1;
var yCount:Number = _cameraHeight / _blockSize <<1;
var tmpField:TextField;
var format:TextFormat = new TextFormat();
format.color = 0x000000;
//var format:TextFormat = new TextFormat('Arial Black', _blockSize, 0x000000);
trace(xCount, yCount);
_textFieldArray = [];
for(var i:uint = 0; i< yCount; i++){
_textFieldArray[i] = [];
for(var j:uint = 0; j < xCount; j++){
tmpField = new TextField;
tmpField.x = j*_blockSize - _pixelOffset;
tmpField.y = i*_blockSize - _pixelOffset;
tmpField.width = _blockSize + _pixelOffset;
tmpField.height = _blockSize + _pixelOffset;
addChild(tmpField);
tmpField.text = '0';
tmpField.setTextFormat(format);
_textFieldArray[i][j] = tmpField;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Event.ENTER_FRAME毎にpixelizeを実行し、画面をテキストで再描画
addEventListener(Event.ENTER_FRAME, pixelize);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
private function pixelize($event:Event):void{
_bitmapData.lock();
_bitmapData.draw(_video);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
var x:int, xx:int, y:int, yy:int;// x軸、y軸の計算に利用
var xCount:uint = 0, yCount:uint = 0;//_textFieldArray内の現在のインデックスを取得するために使用
var bm_height:Number = _bitmapData.height, bm_width:Number = _bitmapData.width;// ビットマップデータの幅、高さ
var r:int, g:int, b:int, count:int;// RGB値それぞれを一時的に保持する変数と、対象になるピクセル数をカウントする変数
var color:ColorRGB = new ColorRGB;// frocessing.color.ColorRGBインスタンス
var currentX:Number, currentY:Number;// xとxx、yとyyの組み合わせによって求められる現在のピクセル位置
var field:TextField;// ビットマップの代わりに出力するテキスト
var format:TextFormat = new TextFormat();// テキストフォーマット(色を設定するために使用)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// 縦横全てのピクセルを検証
for(y = 0; y < bm_height; y += _blockSize){
for(x = 0; x < bm_width; x += _blockSize){
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// _blockSizeで指定したピクセルの色の平均値を計算
r = 0, g = 0, b = 0, count = 0;
for(yy = 0; yy < _blockSize; yy++){
for (xx = 0; xx < _blockSize; xx++){
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// 元のビットマップの範囲を超えないか確認した後、
// xx,yy(それぞれx,y値でオフセット)で指定したピクセル部分の色情報を取得し、
// r,g,b別々に分子に加算して行く。同様に分母も加算して行く。
currentX = x + xx, currentY = y + yy;
if(currentX >= bm_width || currentY >= bm_height || currentX < 0 || currentY < 0) continue;
color.value = _bitmapData.getPixel(currentX, currentY);
r += color.r, g += color.g, b += color.b, count++;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// xx,yyのループで処理した色の平均値を求め、ColorRGBオブジェクトに代入
color.r = r / count, color.g = g /count, color.b = b / count;
field = _textFieldArray[yCount][xCount];
field.text = _kanaList[Math.random()*_kanaList.length | 0]
//field.text = String.fromCharCode((Math.random()*93|0) + 33);
format.color = color.value;
format.size = _blockSize;
format.align = TextFormatAlign.LEFT;
field.setTextFormat(format);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// 平均値でピクセルを再度描画
for(yy = 0; yy < _blockSize; yy ++){
for(xx = 0; xx < _blockSize; xx ++){
currentX = x + xx, currentY = y + yy;
if(currentX >= bm_width || currentY >= bm_height || currentX < 0 || currentY < 0) continue;
_bitmapData.setPixel(currentX, currentY, color.value);
}
}
xCount++;
}
yCount++;
xCount = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
_bitmapData.unlock();
}
}
}