forked from: Thresholdと二値化について

by cyanpon
今更、二値化のコードもないと思いますが、私もASを最近始めたばかり
ですので、わからない事をネットであちこち調べてます。
しかし thresholdを使うのは良いのですがどうも明暗のおかしい妙な
二値化画像ばかりみかけます。

まず、Actionscript 二値化といったキーワードでグーグル検索すると
トップにrsakaneさんのサイトが出てきます。
申し訳ないですが、こちらのページは間違ってます。
http://www40.atwiki.jp/spellbound/pages/168.html

thresholdのパラメータ
"<=", 0x7FFFFF, 0xFF000000, 0xFFFFFF

これ、実際に塗りつぶして試されるとわかりますが、
0x00FFFF(シアン)は輝度に関係なく通って黒になります。同様に 0x00FF00 、 
0x0000FF といった数値も赤輝度が0x80以上でない限り黒くなります。
この方法で二値化するのであれば閾値を0x7F7F7Fに設定する必要があります。

http://aquioux.blog48.fc2.com/blog-entry-694.html
少し前にAquiouxさんがこちらのページで疑問を書かれていますが、
thresholdは大小を32ビットの数値で比較しているだけで、
バイト単位で比較している訳じゃないという事だと思います。

多分、閾値を変えて二値化するのであればRGBの要素それぞれに
threshold使わないといけないのではないでしょうか。

上の例で0x7F7F7Fを閾値にする場合は32ビットの中央値になるので良いのですが、
0x404040といった閾値だと不等号では評価できなくなります。
(※追記 すみません。読み直すと上2行は紛らわしかったです。)

普通は、グレースケールに変換する事が多いと思いますが。
単純に二値化=threshold と考えるのは問題かもしれませんね。

10/03/17 SharaQ
♥0 | Line 153 | Modified 2010-03-18 10:19:47 | MIT License | (replaced)
play

ActionScript3 source code

/**
 * Copyright cyanpon ( http://wonderfl.net/user/cyanpon )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/u2P3
 */

// forked from Sharakusai's Thresholdと二値化について
package {
/*
今更、二値化のコードもないと思いますが、私もASを最近始めたばかり
ですので、わからない事をネットであちこち調べてます。
しかし thresholdを使うのは良いのですがどうも明暗のおかしい妙な
二値化画像ばかりみかけます。

まず、Actionscript 二値化といったキーワードでグーグル検索すると
トップにrsakaneさんのサイトが出てきます。
申し訳ないですが、こちらのページは間違ってます。
http://www40.atwiki.jp/spellbound/pages/168.html

thresholdのパラメータ
"<=", 0x7FFFFF, 0xFF000000, 0xFFFFFF

これ、実際に塗りつぶして試されるとわかりますが、
0x00FFFF(シアン)は輝度に関係なく通って黒になります。同様に 0x00FF00 、 
0x0000FF といった数値も赤輝度が0x80以上でない限り黒くなります。
この方法で二値化するのであれば閾値を0x7F7F7Fに設定する必要があります。

http://aquioux.blog48.fc2.com/blog-entry-694.html
少し前にAquiouxさんがこちらのページで疑問を書かれていますが、
thresholdは大小を32ビットの数値で比較しているだけで、
バイト単位で比較している訳じゃないという事だと思います。

多分、閾値を変えて二値化するのであればRGBの要素それぞれに
threshold使わないといけないのではないでしょうか。

//上の例で0x7F7F7Fを閾値にする場合は32ビットの中央値になるので良いのですが、
//0x404040といった閾値だと不等号では評価できなくなります。
(※追記 すみません。読み直すと上2行は紛らわしかったです。)

普通は、グレースケールに変換する事が多いと思いますが。
単純に二値化=threshold と考えるのは問題かもしれませんね。

10/03/17 SharaQ
*/

import flash.display.Sprite;
import flash.events.*;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.StageScaleMode;
import flash.geom.Point;
import flash.filters.ColorMatrixFilter;

[SWF(width = 465, height = 465, 
frameRate = "16", backgroundColor = 0x000000)]

public class BinarizationExample extends Sprite {

//    private var myFilter:ImageFilter;
    private var myImage:BitmapEX;   //読み込み用
    private var saveImage:BitmapEX; //書き込み用
    private var bmd:BitmapData;
    private var bmp:Bitmap;
    private const url:String              //Lena 画像
        = "http://assets.wonderfl.net/images/related_images/"
        + "e/e0/e085/e0856a21af5022be157e95e36bce38bbc50c1500";

  // initiarize
  public function BinarizationExample() {
    stage.scaleMode = StageScaleMode.NO_SCALE;

    myImage = new BitmapEX();
    myImage.addEventListener(Event.COMPLETE, DrawImage);
    myImage.loadURL(url);
  }

  // main
  private function DrawImage(e:Event):void {
    myImage.removeEventListener(Event.COMPLETE, DrawImage);

    bmd = new BitmapData(myImage.bitmapData.width, 
                             myImage.bitmapData.height);
    bmd.draw(myImage);

    Binarization(bmd,64);

    bmp = new Bitmap(bmd);
    addChild(bmp);
  } //end of function

//
public function Binarization(src:BitmapData , value:int = 0x7F ):void {

    GrayScaleNTSC(src); 

    var valueR:int = value << 16;
    var valueG:int = value << 8;
    var valueB:int = value;

    //threshold, color, mask
    src.threshold(src, src.rect, new Point(), "<=", 
            valueR, 0xFF000000, 0xFF0000, false);
    src.threshold(src, src.rect, new Point(), "<=", 
            valueG, 0xFF000000, 0x00FF00, false);
    src.threshold(src, src.rect, new Point(), "<=", 
            valueB, 0xFF000000, 0x0000FF, false);
    src.threshold(src, src.rect, new Point(), "!=", 
            0x0, 0xFFFFFFFF, 0xFFFFFF, false);

  }

  public function GrayScaleNTSC(src:BitmapData):void {
    var matrix:Array = [
        0.2989, 0.5866, 0.1144, 0, 0,
        0.2989, 0.5866, 0.1144, 0, 0,
        0.2989, 0.5866, 0.1144, 0, 0,
        0,   0,    0,    1, 0
    ];
    src.applyFilter(src, src.rect, new Point(), 
                    new ColorMatrixFilter(matrix));
  }
} // end of class
} // end of Package


////////////////////////////////////////////////////////////////
//
//   画像 I/Oユーティリティ (シングルイメージ) Bitmapサブクラス
//
//
// loadURL   ドメイン上の画像をロード
// loadLocal ローカル画像をロード
// savePNG   PNG形式で保存
// saveJPG   JPG形式で保存
//                                                  by-SharaQ
////////////////////////////////////////////////////////////////

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.net.FileReference;
import flash.net.FileFilter;
import flash.utils.ByteArray;
import flash.display.LoaderInfo;
import com.adobe.images.JPGEncoder;	// as3Corelib
import com.adobe.images.PNGEncoder;

class BitmapEX extends Bitmap {
    private var loadReference:FileReference;
    private var loader:Loader;

    //コンストラクタ
    public function BitmapEX():void {
        loadReference 	= new FileReference();
    }

    //URL上の画像を取得
    public function loadURL(url:String):void {
        var urlloader:Loader = new Loader();
        var urlrequest:URLRequest = new URLRequest(url);
        var loaderContext:LoaderContext = new LoaderContext(true);
        urlloader.load(urlrequest , loaderContext);
        urlloader.contentLoaderInfo.addEventListener(
            Event.COMPLETE, onLoadComplete);
    }
    private function onLoadComplete(e:Event):void {
        var urlloader:Loader = Loader(e.target.loader);	
        var tmp:Bitmap = Bitmap(urlloader.content);        
        this.bitmapData = tmp.bitmapData.clone();
        tmp.bitmapData.dispose();
        var e:Event = new Event(Event.COMPLETE);
        dispatchEvent(e);
    }

    //ローカル画像
    public function LoadLocal():void{
    var fmt:String = "画像ファイル(*.JPG;*.GIF;*.PNG)";
    var ext:String = "*.jpg;*.gif;*.png";
    var filefilter:FileFilter = new FileFilter(fmt, ext);
    loadReference.addEventListener(Event.SELECT, onLoadFileSelect);
    loadReference.browse([filefilter]);
    }
    private function onLoadFileSelect(e:Event):void{
    loadReference.removeEventListener(Event.SELECT, onLoadFileSelect);
    loadReference.addEventListener(Event.COMPLETE, onLocalComplete);
    loadReference.load();
        }
    private function onLocalComplete(e:Event):void {
    loadReference.removeEventListener(Event.COMPLETE, onLocalComplete);
    loader = new Loader();
    loader.contentLoaderInfo.addEventListener(
            Event.COMPLETE,onLocalLoaded); 
        loader.loadBytes(loadReference.data);
        }
    private function onLocalLoaded(e:Event):void {
    var loaderInfo:LoaderInfo = (e.target as LoaderInfo);
    loader.contentLoaderInfo.removeEventListener(
            Event.COMPLETE,onLocalLoaded);
    var tmp:BitmapData = new BitmapData(loader.width, loader.height);
    tmp.draw(loader.content);
    this.bitmapData = tmp.clone();

    tmp.dispose();
    //addEventListerner の指定先に返す。引数を忘れないように(エラーにならない)
        var e:Event = new Event(Event.COMPLETE);
        dispatchEvent(e);
        }

    //PNG イメージで保存
    public function SavePNG():void{
    if (!this.bitmapData) return;

    var encoder:Object = new Object();
    var defaultName:String;

    encoder.encode = PNGEncoder.encode;
    defaultName = "Sample.png";

    var imageBytes:ByteArray = encoder.encode(this.bitmapData);
    var fileRef:FileReference = new FileReference();
    fileRef.save(imageBytes, defaultName);

    var e:Event = new Event(Event.COMPLETE);
    dispatchEvent(e);
    }

    //JPG イメージで保存
    private function SaveJPG():void{
    if (! this.bitmapData) return;
    var encoder:Object = new Object();
    var defaultName:String;

    var je:*;
    je = new JPGEncoder(100);
    encoder.encode = je.encode;
    defaultName = "Sample.jpg";

    var imageBytes:ByteArray = encoder.encode(this.bitmapData);
    var fileRef:FileReference = new FileReference();
    fileRef.save(imageBytes, defaultName);

    var e:Event = new Event(Event.COMPLETE);
    dispatchEvent(e);
}
}