色名で描画


ウェブカムでとった画像の色を、該当する近い色名の形で描画する。

色名で描画 – wonderfl build flash online

色番号はwikipediaのJIS慣用色名を参考にした。
http://ja.wikipedia.org/wiki/JIS慣用色名

近似色の取得はActionScript入門Wikiを参考にした。
http://www40.atwiki.jp/spellbound/pages/293.html

[sourcecode language=”as3″]
package
{
import flash.display.Sprite;
import flash.events.Event;
import net.hires.debug.Stats;

/**
* …
* @author umhr
*/
//[SWF(width = 465, height = 465, backgroundColor = 0x000000, frameRate = 60)]
[SWF(frameRate = 60)]
public class WonderflMain extends Sprite
{

public function WonderflMain():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}

private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point

stage.scaleMode = "noScale";
stage.align = "TL";

addChild(new Canvas());
addChild(new Stats());
}

}

}

import flash.display.Sprite;
import flash.events.Event;
/**
* …
* @author umhr
*/
class Canvas extends Sprite
{
private var _drawCanvas:DrawCanvas = new DrawCanvas();
private var _cameraManager:CameraManager = CameraManager.getInstance();
public function Canvas()
{
init();
}
private function init():void
{
if (stage) onInit();
else addEventListener(Event.ADDED_TO_STAGE, onInit);
}

private function onInit(event:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, onInit);
// entry point

addChild(_cameraManager);

addChild(_drawCanvas);
addEventListener(Event.ENTER_FRAME, enterFrame);
}

private function enterFrame(e:Event):void
{
if (!_cameraManager.activating) {
return;
}
_drawCanvas.enter();
_cameraManager.enter();
}
}

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Matrix;
/**
* …
* @author umhr
*/
class DrawCanvas extends Sprite
{
private var _bitmap:Bitmap;
private var _colorBitmapCollector:ColorBitmapCollector = new ColorBitmapCollector();
//private const FADE:ColorTransform = new ColorTransform(1, 1, 1, 1, 1, 1, 1);
private var _filter:Filter;
public function DrawCanvas()
{
init();
}
private function init():void
{
if (stage) onInit();
else addEventListener(Event.ADDED_TO_STAGE, onInit);
}

private function onInit(event:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, onInit);
// entry point

_bitmap = new Bitmap(new BitmapData(stage.stageWidth, stage.stageHeight,true,0x0));
addChild(_bitmap);

_filter = new Filter(stage.stageWidth, stage.stageHeight);

}
public function enter():void {
// ブラーをかける
_bitmap.bitmapData = _filter.blurFilter(_bitmap.bitmapData);

for (var i:int = 0; i < 100; i++)
{
draw(_bitmap.bitmapData);
}
}

private function draw(targetBitmapData:BitmapData):void {
var tx:int = Math.random() * stage.stageWidth;
var ty:int = Math.random() * stage.stageHeight;
var rgb:uint = CameraManager.getInstance().getPixel(tx, ty);
var bitmap:Bitmap = _colorBitmapCollector.getNearBitmap(rgb);

targetBitmapData.draw(bitmap, new Matrix(1, 0, 0, 1, tx – bitmap.width * 0.5, ty – bitmap.height * 0.5));

}

}

import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.ActivityEvent;
import flash.events.Event;
import flash.media.Camera;
import flash.media.Video;
/**
* …
* @author umhr
*/
class CameraManager extends Sprite
{
private static var _instance:CameraManager;
public function CameraManager(block:SingletonBlock){init();}
public static function getInstance():CameraManager{
if ( _instance == null ) {_instance = new CameraManager(new SingletonBlock());};
return _instance;
}

private var _video:Video = new Video();
private var _bitmapData:BitmapData;
private var _scale:Number = 1;
public var activating:Boolean = false;
private var _count:uint = 0;
private var _dx:Number = 0;
private var _dy:Number = 0;
private function init():void
{
if (stage) onInit();
else addEventListener(Event.ADDED_TO_STAGE, onInit);
}

private function onInit(event:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, onInit);
// entry point
var camera:Camera = Camera.getCamera();
//カメラの存在を確認
if (camera) {
camera.setMode(320, 240, 15);
camera.addEventListener(ActivityEvent.ACTIVITY, camera_activity);
_video.attachCamera(camera);
_scale = Math.min(320 / stage.stageWidth, 240 / stage.stageHeight);
_dx = (320 – stage.stageWidth * _scale) * 0.5;
_dy = (240 – stage.stageHeight * _scale) * 0.5;

_bitmapData = new BitmapData(320, 240);
} else {
trace("カメラが見つかりませんでした。");
}
}

private function camera_activity(event:ActivityEvent):void
{
activating = true;
}

/**
* カメラで取得した結果を_bitmapDataに保持する。
*/
public function enter():void {
if (!activating) { return };
if (_count % 4 == 0) {
_bitmapData.draw(_video);
}
_count ++;
}

/**
* 対応する座標の色を返す。
* @param x
* @param y
* @return
*/
public function getPixel(x:int, y:int):int {
if (!activating) { return 0x0 };
var tx:int = x * _scale + _dx;
var ty:int = y * _scale + _dy;
return _bitmapData.getPixel(tx, ty);
}
}

class SingletonBlock { };

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.text.TextField;
import flash.text.TextFormat;
/**
* rgbに対応したbitmapを保持します。
* …
* @author umhr
*/
class ColorBitmapCollector
{

private var _textSampleList:Vector.<Bitmap>;
private var _rgbSeparatList:Vector.<Vector.<int>>;
private var _indexFromRGBList:Vector.<int>;
public function ColorBitmapCollector()
{
init();
}

private function init():void
{
// 色名、色番号に対応した画像を用意しておく
var textField:TextField = new TextField();
textField.defaultTextFormat = new TextFormat("_明朝", 16);
textField.autoSize = "left";

_textSampleList = new Vector.<Bitmap>();

var japaneseColors:JapaneseColors = new JapaneseColors();

var n:int = japaneseColors.colorNameList.length;
_rgbSeparatList = new Vector.<Vector.<int>>(n, true);
for (var i:int = 0; i < n; i++)
{
textField.text = japaneseColors.colorNameList[i];
textField.textColor = japaneseColors.textColorList[i];
var bitmap:Bitmap = new Bitmap(new BitmapData(textField.textWidth, textField.textHeight+3, true, 0x0));
bitmap.bitmapData.draw(textField);
_textSampleList.push(bitmap);
_rgbSeparatList[i] = rgbSeparater(japaneseColors.textColorList[i]);
}

// 色(rgb)に対応した近似色のindexを保持しておくための処理
_indexFromRGBList = new Vector.<int>(0xFFFFFF + 1, true);
n = 0xFFFFFF + 1;
for (i = 0; i < n; i++)
{
_indexFromRGBList[i] = -1;
}
}

/**
* 引数rgbに近似色のbitmapを返します。
* @param rgb
* @return
*/
public function getNearBitmap(rgb:int):Bitmap {
return _textSampleList[indexFromRGB(rgb)];
}

/**
* 色と色の距離を求める。相対的な値が欲しいだけなので、平方根は求めない。
* http://www40.atwiki.jp/spellbound/pages/293.html
* @param rgbList
* @param array
* @return
*/
private function getColotDistance(rgbList:Vector.<int>, array:Vector.<int>):Number
{
var r:int = rgbList[0] – array[0];
var g:int = rgbList[1] – array[1];
var b:int = rgbList[2] – array[2];
return r * r + g * g + b * b;
}

/**
* 色を分解して返す。
* @param rgb
* @return
*/
private function rgbSeparater(rgb:int):Vector.<int> {
return Vector.<int>([rgb >> 16 & 0xFF, rgb >> 8 & 0xFF, rgb & 0xFF]);
}

private var count:int = 0;
private function indexFromRGB(rgb:int):int {
var index:int = _indexFromRGBList[rgb];

// 以前に近似色を探索し、該当indexを保持していればその値を返す。
if ( -1 < index) {
return index;
}

// 以前に近似色を探していない場合の処理。

var rgbList:Vector.<int> = rgbSeparater(rgb);

// すべての色と比較
var n:int = _rgbSeparatList.length;
var distanceList:Array = new Array(n);
for (var i:int = 0; i < n; i++)
{
distanceList[i] = getColotDistance(rgbList, _rgbSeparatList[i]);
}

// 一番近い距離の色を求める。
index = distanceList.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY)[0];

_indexFromRGBList[rgb] = index;

count ++;
if (count%1000 == 0) {
trace("取得済みindex数:" + count);
}

return index;
}
}

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.filters.BlurFilter;
/**
* ブラーフィルターをかけて返します。
* …
* @author umhr
*/
class Filter
{
private var _filerBitmap:Bitmap;
private var _tempBitmapData:BitmapData;
public function Filter(width:int, height:int)
{
init(width, height);
}

private function init(width:int, height:int):void
{
_filerBitmap = new Bitmap(new BitmapData(width, height));
_filerBitmap.filters = [new BlurFilter(2, 2)];

_tempBitmapData = new BitmapData(_filerBitmap.width, _filerBitmap.height)
}

/**
* ブラーフィルターをかけて返します。
* @param bitmapData
* @return
*/
public function blurFilter(bitmapData:BitmapData):BitmapData {
_filerBitmap.bitmapData = bitmapData;
_tempBitmapData.draw(_filerBitmap);
return _tempBitmapData;
}
}

/**
* 色番号と色名を保持します。
*
* 色番号
* http://ja.wikipedia.org/wiki/JIS%E6%85%A3%E7%94%A8%E8%89%B2%E5%90%8D
*
* JIS慣用色名の色見本(和名) – JIS Color Sample
* http://www.color-sample.com/color_coloring/whole/jiscolor1.html
* …
* @author umhr
*/
class JapaneseColors
{
/**
* 色番号リスト
*/
public var textColorList:Array = [];
/**
* 色の和名リスト
*/
public var colorNameList:Array = [];
public function JapaneseColors()
{
init();
}

private function init():void
{
var colorsList:Array = [0xF9A1D0,"鴇",0xCB4B94,"躑躅",0xFFDBED,"桜",0xD34778,"薔薇",0xE3557F,"韓紅",0xFF87A0,"珊瑚",0xE08899,"紅梅",0xE38698,"桃",0xBD1E48,"紅",0xB92946,"紅赤",0xAE3846,"臙脂",0x974B52,"蘇芳",0xA0283A,"茜",0xBF1E33,"赤",0xED514E,"朱",0xA14641,"紅樺",0xEE5145,"紅緋",0xD3503C,"鉛丹",0x703B32,"紅海老茶",0x7D483E,"鳶",0x946259,"小豆",0x8A4031,"弁柄",0x6D3D33,"海老茶",0xED542A,"金赤",0xB15237,"赤茶",0x923A21,"赤錆",0xEF6D3E,"黄丹",0xED551B,"赤橙",0xE06030,"柿",0xB97761,"肉桂",0xBD4A1D,"樺",0x974E33,"煉瓦",0x664134,"錆",0x8A604F,"檜皮",0x754C38,"栗",0xE45E00,"黄赤",0xBA6432,"代赭",0xB67A52,"駱駝",0xBB6421,"黄茶",0xF4BE9B,"肌",0xFD7E00,"橙",0x866955,"灰茶",0x734E30,"茶",0x594639,"焦茶",0xFFA75E,"柑子",0xDDA273,"杏",0xFA8000,"蜜柑",0x763900,"褐",0xA96E2D,"土",0xD9A46D,"小麦",0xC67400,"琥珀",0xC47600,"金茶",0xFABE6F,"卵",0xFFA500,"山吹",0xC18A39,"黄土",0x897868,"朽葉",0xFFB500,"向日葵",0xFCAC00,"鬱金",0xC9B9A8,"砂",0xCDA966,"芥子",0xFFBE00,"黄",0xFFBE00,"蒲公英",0x70613A,"鶯茶",0xFAD43A,"中黄",0xEED67E,"刈安",0xD9CB65,"黄檗",0x736F55,"海松",0xC2C05C,"鶸",0x71714A,"鶯",0xBDBF92,"抹茶",0xB9C42F,"黄緑",0x7A7F46,"苔",0xA9B735,"若草",0x96AA3D,"萌黄",0x72814B,"草",0xAFC297,"若葉",0x6E815C,"松葉",0xCADBCF,"白緑",0x4DB56A,"緑",0x357C4C,"常磐",0x5F836D,"緑青",0x4A6956,"千歳緑",0x005731,"深緑",0x15543B,"萌黄",0x49A581,"若竹",0x80AA9F,"青磁",0x7AAAAC,"青竹",0x244344,"鉄",0x0090A8,"青緑",0x6C8D9B,"錆浅葱",0x7A99AA,"水浅葱",0x69AAC6,"新橋",0x0087AA,"浅葱",0x84B5CF,"白群",0x166A88,"納戸",0x8CB4CE,"甕覗",0xA9CEEC,"水",0x5E7184,"藍鼠",0x95C0EC,"空",0x0067C0,"青",0x2E4B71,"藍",0x20324E,"濃藍",0x92AFE4,"勿忘草",0x3D7CCE,"露草",0x3C639B,"縹",0x3D496B,"紺青",0x3451A4,"瑠璃",0x324784,"瑠璃紺",0x333C5E,"紺",0x4C5DAB,"杜若",0x383C57,"勝",0x414FA3,"群青",0x232538,"鉄紺",0x6869A8,"藤納戸",0x4A49AD,"桔梗",0x35357D,"紺藍",0xA09BD8,"藤",0x948BDB,"藤紫",0x704CBC,"青紫",0x6D52AB,"菫",0x675D7E,"鳩羽",0x7051AA,"菖蒲",0x5F4C86,"江戸紫",0xA260BF,"紫",0x775686,"古代紫",0x47384F,"茄子紺",0x402949,"紫紺",0xC27BC8,"菖蒲",0xC24DAE,"牡丹",0xC54EA0,"赤紫",0xF1F1F1,"白",0xF2E8EC,"胡粉",0xF0E2E0,"生成",0xE3D4CA,"象牙",0xA0A0A0,"銀鼠",0x9F9190,"茶鼠",0x868686,"鼠",0x787C7A,"利休鼠",0x797A88,"鉛",0x797979,"灰",0x605448,"煤竹",0x3E2E28,"黒茶",0x313131,"墨",0x262626,"黒",0x262626,"鉄黒"];

var n:int = colorsList.length * 0.5;
for (var i:int = 0; i < n; i++)
{
textColorList.push(colorsList[i * 2]);
colorNameList.push(colorsList[i * 2 + 1]);
}
}

}

[/sourcecode]