forked from: forked from: 画像を絵画調に変換
画像を絵画調に変換
画像をクリックすると、次の画像へ。
解説など:http://game.g.hatena.ne.jp/Nao_u/20091229
副産物
/**
* Copyright uwi ( http://wonderfl.net/user/uwi )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/qUGS
*/
// forked from uwi's forked from: 画像を絵画調に変換
// forked from Nao_u's 画像を絵画調に変換
//
// 画像を絵画調に変換
//
// 画像をクリックすると、次の画像へ。
//
//
// 解説など:http://game.g.hatena.ne.jp/Nao_u/20091229
//
// 副産物
package {
import flash.display.Sprite;
import flash.events.*;
[SWF(width="465", height="465", backgroundColor="0xFFFFFF", frameRate="30")]
public class FlashTest extends Sprite {
public function FlashTest() {
Main = this;
startLoad();
stage.addEventListener(Event.ENTER_FRAME,update);
stage.addEventListener(MouseEvent.MOUSE_DOWN, isClick );
}
}
}
function isClick(event:MouseEvent):void{
Text.text = "生成中...";
bLoad = false;
startLoad();
}
import flash.display.*;
import flash.events.*
import flash.text.TextField;
import flash.geom.*;
import flash.utils.getTimer;
import flash.net.*;
import flash.filters.*;
var Main:Sprite;
var SCREEN_W:Number = 465;
var SCREEN_H:Number = 465;
var Text:TextField
var View: Bitmap;
var BmpData: BitmapData;
var BmpData2: BitmapData;
var BmpDataMono: BitmapData;
var BmpDataEdge: BitmapData;
var BmpDataTmp: BitmapData;
var BITMAP_W:int = SCREEN_W;
var BITMAP_H:int = SCREEN_H;
var loaderA:Loader;
var loaderB:Loader;
var bLoad:Boolean = false;
var No:int = 0;
function startLoad():void{
loaderA = new Loader();
var url:String;
switch(No){
case 0: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090326/20090326044849.jpg"; break;
case 1: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090913/20090913133305.jpg"; break;
case 2: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090817/20090817090823.jpg"; break;
case 3: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090817/20080716105600.jpg"; break;
case 4: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090326/20090326042031.jpg"; break;
case 5: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090817/20090327043047.jpg"; break;
case 6: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090326/20080810100737.jpg"; break;
case 7: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090817/20080809101700.jpg"; break;
case 8: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090326/20090327102950.jpg"; break;
case 9: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090326/20090327090702.jpg"; break;
case 10: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090326/20080716102900.jpg"; break;
case 11: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090326/20090327091952.jpg"; break;
case 12: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090913/20090913133218.jpg"; break;
case 13: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090326/20090327043118.jpg"; break;
case 14: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090326/20090326052814.jpg"; break;
case 15: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090326/20080810090405.jpg"; break;
case 16: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090326/20080106055925.jpg"; break;
case 17: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090326/20080106044103.jpg"; break;
case 18: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090817/20090817091054.jpg"; break;
case 19: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090817/20091004065300.jpg"; break;
case 20: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090817/20091004070000.jpg"; break;
case 21: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090817/20090815193507.jpg"; break;
case 22: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090817/20090326084145.jpg"; break;
case 23: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090817/20090326072406.jpg"; break;
case 24: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090817/20080810113647.jpg"; break;
case 25: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090817/20080716105000.jpg"; break;
case 26: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090817/20080115004653.jpg"; break;
case 27: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090817/20080716101100.jpg"; break;
case 28: url = "http://img.f.hatena.ne.jp/images/fotolife/N/Nao_u/20090817/20080716111200.jpg"; break;
}
No++;
if( No == 29 ) No = 0;
loaderA.load( new URLRequest(url) );
loaderA.contentLoaderInfo.addEventListener( Event.COMPLETE, loadComplete );
}
function loadComplete(e:Event):void {
loaderB = new Loader();
loaderB.contentLoaderInfo.addEventListener(Event.INIT, initialize);
loaderB.loadBytes(loaderA.contentLoaderInfo.bytes);
}
function initialize(event:Event):void
{
var loader:Loader = loaderB;
BmpData = new BitmapData(BITMAP_W, BITMAP_W, false);
BmpData.draw(loader);
View = new Bitmap(BmpData);
View.scaleX = 1.0;
View.scaleY = 1.0;
Main.addChild(View);
BmpData2 = new BitmapData(loader.width, loader.height, false);
BmpDataMono = new BitmapData(loader.width, loader.height, false);
BmpDataEdge = new BitmapData(loader.width, loader.height, false);
BmpDataTmp = new BitmapData(loader.width, loader.height, false);
Text = new TextField();
Text.text = "画像変換中・・・しばらくお待ちください";
Text.autoSize = "left";
Main.addChild(Text);
Cnt=0;
bLoad = true;
}
var Cnt:int;
function update(e :Event):void{
if( bLoad == false ){
return;
}
Cnt++;
if( Cnt == 3 ){
var time:int = getTimer();
var cont:Number = 64;
var mul:Number = 128 + cont;
// モノクロ画像を生成
FilterMono( BmpData, BmpDataMono );
// モノクロ画像からエッジ抽出画像を生成
FilterEdge( BmpDataMono, BmpDataEdge );
// 元絵からぼかし画像を生成(5x5を2パス)
// Filter3( BmpData, BmpData2 );
// Filter3( BmpData2, BmpData );
// ぼかした画像にエッジ抽出画像を乗算
var matrix : Matrix = new Matrix(1,0,0,1,0,0);
var color : ColorTransform = new ColorTransform(1,1,1,1,0,0,0,0);
BmpData.draw(BmpDataEdge, matrix, color, BlendMode.MULTIPLY);
var endTime:int = getTimer() - time;
Text.text = "生成時間:" + endTime + "[ms]";
}
}
// モノクロ画像を生成
function FilterMono( inBmp:BitmapData, outBmp:BitmapData):void{
var cmf : ColorMatrixFilter = new ColorMatrixFilter([
0.298912, 0.586611, 0.114477, 0, 0,
0.298912, 0.586611, 0.114477, 0, 0,
0.298912, 0.586611, 0.114477, 0, 0,
0.298912, 0.586611, 0.114477, 0, 0
]);
outBmp.lock();
outBmp.applyFilter(inBmp, inBmp.rect, new Point(), cmf);
outBmp.unlock();
}
// エッジ抽出画像を生成
function FilterEdge( inBmp:BitmapData, outBmp:BitmapData):void{
var iB:BitmapData;
var oB:BitmapData;
var sum:Number = 0;
var i : uint;
var cf1 : ConvolutionFilter = new ConvolutionFilter(3, 3, [
-1, 0, 1,
-2, 0, 2,
-1, 0, 1
], 1, 127);
var cf2 : ConvolutionFilter = new ConvolutionFilter(3, 3, [
-1, -2, -1,
0, 0, 0,
1, 2, 1
], 1, 127);
var mSquare : Array = new Array(256);
for(i = 0;i < 256;i++){
mSquare[i] = Math.min((i - 127) * (i - 127) / 15.9375, 255);
}
var m : Array = new Array(256);
for(i = 0;i < 255;i++){
m[i] = 0x000000;
}
m[255] = 0x737373;
outBmp.lock();
var tempB: BitmapData = inBmp.clone();
outBmp.applyFilter(inBmp, inBmp.rect, new Point(), cf1);
outBmp.paletteMap(outBmp, outBmp.rect, new Point(), mSquare, mSquare, mSquare); // 2乗
tempB.applyFilter(inBmp, inBmp.rect, new Point(), cf2);
tempB.paletteMap(tempB, tempB.rect, new Point(), mSquare, mSquare, mSquare); // 2乗
outBmp.draw(tempB, null, null, BlendMode.ADD);
tempB.dispose();
outBmp.paletteMap(outBmp, outBmp.rect, new Point(), null, null, m);
outBmp.unlock();
var median : ConvolutionFilter = new ConvolutionFilter(3, 3, [
1, 1, 1,
1, 1, 1,
1, 1, 1
]);
BmpDataTmp.applyFilter(outBmp, outBmp.rect, new Point(), median);
/*
// メディアンフィルター(もどき)でノイズ除去
BmpData.lock();
iB = outBmp;
oB = BmpDataTmp;
for( var x:int=0; x<BITMAP_W; x++ ){
for( var y:int=0; y<BITMAP_H; y++ ){
sum = 0;
var c0:Color = new Color( iB.getPixel(x-1, y-1) );
var c1:Color = new Color( iB.getPixel(x, y-1) );
var c2:Color = new Color( iB.getPixel(x+1, y-1) );
var c3:Color = new Color( iB.getPixel(x-1, y) );
var c4:Color = new Color( iB.getPixel(x , y) );
var c5:Color = new Color( iB.getPixel(x+1, y) );
var c6:Color = new Color( iB.getPixel(x-1, y+1) );
var c7:Color = new Color( iB.getPixel(x, y+1) );
var c8:Color = new Color( iB.getPixel(x+1, y+1) );
if( c0.r > 0.5 ) sum += 1.0;
if( c1.r > 0.5 ) sum += 1.0;
if( c2.r > 0.5 ) sum += 1.0;
if( c3.r > 0.5 ) sum += 1.0;
if( c4.r > 0.5 ) sum += 1.0;
if( c5.r > 0.5 ) sum += 1.0;
if( c6.r > 0.5 ) sum += 1.0;
if( c7.r > 0.5 ) sum += 1.0;
if( c8.r > 0.5 ) sum += 1.0;
if( sum < 1 ) oB.setPixel(x, y, 0 );
else oB.setPixel(x, y, c4.getInt() );
}
}
BmpData.unlock();
*/
var b:Color = new Color(0);
var col:Color = new Color(0);
var s:Number = 0;
var w:Number = 0;
// ぼかし
BmpData.lock();
iB = BmpDataTmp;
oB = outBmp;
for( var x:int=0; x<BITMAP_W; x++ ){
for( var y:int=0; y<BITMAP_H; y++ ){
sum = 0;
col.r = col.g = col.b = 0;
b.set( iB.getPixel(x, y) );
for( var lx:int=-2; lx<=1; lx++ ){
for( var ly:int=-2; ly<=2; ly++ ){
var px:int = x+lx;
var py:int = y+ly;
if( px < 0 || px >= BITMAP_W || py < 0 || py >= BITMAP_H ) break;
var c:Color = new Color( iB.getPixel(px, py) );
s = c.g - b.g;
if( s < 0 ) s = -s;
w = 1;// - s*s;
if( lx == -2 ) w *= 0.4;
if( ly == -2 || ly == 2 ) w *= 0.4;
col.r += c.r * w;
col.g += c.g * w;
col.b += c.b * w;
sum += w;
}
}
var mul:Number = 1.0 / sum;
col.r *= mul;
col.g *= mul;
col.b *= mul;
oB.setPixel(x, y, col.getInt() );
}
}
BmpData.unlock();
}
// ぼかしフィルタ(バイラテラルフィルタっぽい感じ)
function Filter3( inBmp:BitmapData, outBmp:BitmapData):void{
var b:Color = new Color(0);
var col:Color = new Color(0);
var c:Color = new Color( 0 );
var sum:Number = 0;
var s:Number = 0;
var w:Number = 0;
BmpData.lock();
for( var x:int=0; x<BITMAP_W; x++ ){
for( var y:int=0; y<BITMAP_H; y++ ){
sum = 0;
col.r = col.g = col.b = 0;
b.set( inBmp.getPixel(x, y) );
for( var lx:int=-5; lx<=5; lx++ ){
for( var ly:int=-5; ly<=5; ly++ ){
c.set( inBmp.getPixel(x+lx, y+ly) );
s = c.g - b.g;
if( s < 0 ) s = -s;
w = 1 - s*s*s;
col.r += c.r * w;
col.g += c.g * w;
col.b += c.b * w;
sum += w;
}
}
var mul:Number = 1.0 / sum;
col.r *= mul;
col.g *= mul;
col.b *= mul;
outBmp.setPixel(x, y, col.getInt() );
}
}
BmpData.unlock();
}
// 色クラス
class Color{
public var r:Number;
public var g:Number;
public var b:Number;
public function Color( c:int ){
r = ((c & 0xff0000)>>16)*0.003921568627;
g = ((c & 0x00ff00)>>8)*0.003921568627;
b = ((c & 0x0000ff))*0.003921568627;
}
public function set( c:int ):void{
r = ((c & 0xff0000)>>16)*0.003921568627;
g = ((c & 0x00ff00)>>8)*0.003921568627;
b = ((c & 0x0000ff))*0.003921568627;
}
public function getInt():int{
if( r > 1.0 ) r = 1.0;
if( g > 1.0 ) g = 1.0;
if( b > 1.0 ) b = 1.0;
if( r < 0.0 ) r = 0.0;
if( g < 0.0 ) g = 0.0;
if( b < 0.0 ) b = 0.0;
var col:int = ((r*255) << 16) + ((g*255)<<8) + (b*255);
return col;
}
}