>> NightVision.swf (要 Flash Player 10 & Webカメラ、負荷が高めなので注意してください)
PhotoshopによるナイトビジョンエフェクトをFlashで再現。
赤外線暗視ゴーグルをかけた時に見られるような画像に加工します。
PhotoshopのNightVisionプラグインは以下のサイトで無料配布されています。
VanDerLee – Home / Plug-ins / NightVision – Add realistic night-goggle and imaging distortion to images.
インタレースとゴースト(二重映り)の表現は、去年書いた VTR調変換 – AS3.0 のコードを応用しました。
最初は赤と青チャンネルの値を半分にしていたんですが、それだと緑が強くなりすぎてしまうので、
赤と青チャンネルをガンマ補正してから最後にノイズを少し乗せてやると雰囲気が出ます。
色味を変えるだけならColorTransformを使えば簡単にできますが、
インタレースとゴーストを表現するためには直接ピクセルデータを操作した方が効率が良いようです。
・ソースコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
package { import __AS3__.vec.Vector; import flash.display.*; import flash.events.Event; import flash.geom.*; import flash.media.*; import flash.text.*; import flash.utils.ByteArray; [SWF(width = "640", height = "300", backgroundColor = "#000000", frameRate = "30")] public class NightVision extends Sprite { private var capture:Camera; private var video:Video; private var output:Bitmap; private var imageData:ByteArray; private var noiseData:BitmapData; private var pt:Point; private var tbl:Vector.<int>; public function NightVision() { stage.scaleMode = "noScale"; capture = Camera.getCamera(); tbl = new Vector.<int>(256, true); var gamma:Number = 1.5; // ガンマ補正用パラメータ、0に近いほど暗くなる for(var i:int=0; i<256; i++) { // ガンマ補正用変換テーブル作成 tbl[i] = Math.pow(i/255.0, gamma)*255.0; } if(capture != null) { capture.setMode(320, 240, 30); video = new Video(); video.attachCamera(capture); addChild(video); output = new Bitmap(new BitmapData(video.width, video.height, false)); imageData = new ByteArray(); noiseData = new BitmapData(video.width, video.height, false); pt = new Point(); addChild(output); output.x = video.width; this.addEventListener(Event.ENTER_FRAME, execute, false, 0, true); } } private function execute(e:Event):void { output.bitmapData.draw(video); imageData = output.bitmapData.getPixels(output.bitmapData.rect); filterNightVision(imageData, 4, 20, 6); imageData.position = 0; output.bitmapData.setPixels(output.bitmapData.rect, imageData); noiseData.noise(Math.random()*0xff, 0, 255, BitmapDataChannel.GREEN, false); output.bitmapData.merge(noiseData, noiseData.rect, pt, 0, 32, 0, 0); } // img:画像データ, thick:走査線の太さ, contrast:行間のコントラスト(インタレース), ghost:ゴーストの位置ズレ量 private function filterNightVision(img:ByteArray, thick:int, contrast:int, ghost:int):void { var w:int = video.width, h:int = video.height; var g:uint = 0, pos:uint = 0, f:uint = 0; for(var y:int=0; y<h; y++) { f = y%thick<<1; for(var x:int=0; x<w; x++) { pos = (w*y<<2) + (x<<2) + 2; // 緑チャンネルのインデックス(一次元) g = img[pos] + img[pos + (ghost<<2)]>>1; if(f<thick) { g += contrast; if(g>255) g = 255; } // 赤・青チャンネルをガンマ補正 img[pos - 1] = tbl[img[pos - 1] >>= 1]; img[pos] = g; img[pos + 1] = tbl[img[pos + 1] >>= 1]; } } } } } |