AS3 - あらためてラベリング処理

火曜に、imglのうっちーとあらためてラベリング処理ってどうやんのよという話をしていて、あらためてAS3で書き直した。
ただし、ラベルの衝突処理はまだやっていない。

ラベリング処理について→s.h.log: Proce55ing - 2値化画像を4近傍ラベリング処理してパーツ抜き出し

今まで、ラベルそのものを2次元のint配列で管理してたけど、今回はBitmapDataオブジェクトとして保存する様にしてみた。BitmapDataならx,y座標で要素にアクセスできるし、ピクセルはuint型なので都合がいい。

■できたもの
download => fla, as, swf (FlashDevelop3.0.0 Beta5 + FlashCS3)

年末年始作ったカメラから画像処理のサンプルを元に改造した。
webcamから撮影してBitmapDataにして、1ピクセルずつ走査して真っ白(0×00FFFFFF)のピクセルを検出。
さらにラベリング処理をして、「ピクセルのかたまり」毎に番号をつける。

(0×00FFFFFFは蛍光灯を撮影すると良いです)
labelinglabelinglabeling

今回はノイズを飛ばしたりしていないので、右の本棚の小さな白にも反応してしまって28個とか検出される
labeling

ラベルの衝突時の処理もしていないので、左上が空いた弧の様な形の時に割れてしまう
labeling
この辺はまたの機会に。


■動きます(USBカメラが必要)

■コード
ColorPicker.as

package {
    import fl.controls.Button;
    import fl.controls.NumericStepper;
    import flash.events.*;
    import flash.media.*;
    import flash.geom.Point;
    import flash.utils.*;
    import flash.display.*;
    import flash.filters.*;
    public class ColorPicker extends Sprite {
        private var cam:Camera; // カメラ
        private var video:Video; // カメラからの画像を表示
        private var bmp:Bitmap; // 表示
        private var bmd:BitmapData; // 中身のデータ
        private var labels:BitmapData; // bmdと同サイズのラベル
        private var color:int = 0×00ffffff; // 選択する色(白)
        
        private var _numericStepperLabelNum:NumericStepper;
        private var _buttonSnapshot:Button;
        
        /* IDEが生成したオブジェクトを関連づけ */
        public function link_ide_obj() {
            this._numericStepperLabelNum = numericStepperLabelNum;
            this._buttonSnapshot = buttonSnapshot;
        }
        
        public function ColorPicker() {
            stage.scaleMode = StageScaleMode.EXACT_FIT; // 伸縮する
            //stage.scaleMode = StageScaleMode.NO_SCALE; // 伸縮しない
            stage.align = StageAlign.TOP_LEFT; // 左上から
            
            link_ide_obj(); // IDEが生成したオブジェクトを関連づけ
            
            cam = Camera.getCamera();
            cam.setMode(800,600,24,true);// 24FPS
            cam.setQuality(0,100);
            
            video = new Video(200,150); // bitmap計算用の小さいビデオ
            video.attachCamera(cam);
            this.addChild(video); // videoを表示
            
            _buttonSnapshot.addEventListener(MouseEvent.CLICK, snapShot); // 撮影の関数登録
            bmd = new BitmapData(video.width, video.height);
            bmp = new Bitmap(bmd); // BitmapDataをBitampに登録
            this.addChild(bmp); // Bitmapを表示
            bmp.x = video.width + 10;
            
            // ラベル番号の選択GUI
            _numericStepperLabelNum.enabled = false;
            _numericStepperLabelNum.addEventListener(Event.CHANGE, function() { 
                showSelectedLabel(_numericStepperLabelNum.value);
            } );
        }
        
        /* 撮影 */
        public function snapShot(e:Event){
            bmd.draw(video); // カメラから制止画をキャプチャ
            labeling();
            showSelectedLabel(_numericStepperLabelNum.value);
            _numericStepperLabelNum.enabled = true;
        }
        
        /* 4近傍ラベリング処理 */
        public function labeling(){
            labels = new BitmapData(bmd.width, bmd.height, false, 0); // transparent = false
            var label:int = 0;
            var x:int, y:int;
            bmd.lock(); // 表示の更新を止める。これやらないとえらい事になる
            for (y = 0; y < bmd.height; y++) {
                for (x = 0; x < bmd.width; x++) {
                    if(bmd.getPixel(x,y) == color){ // 選択した色の時(今回は白)
                        if (x > 0 && labels.getPixel(x - 1, y) > 0) { // 左チェック
                            labels.setPixel(x, y, labels.getPixel(x - 1, y)); // ラベルをコピー
                        }
                        else if (x > 0 && y > 0 && labels.getPixel(x - 1, y - 1) > 0) { // 左上
                            labels.setPixel(x, y, labels.getPixel(x - 1, y - 1));
                        }
                        else if (y > 0 && labels.getPixel(x, y - 1) > 0) { // 上
                            labels.setPixel(x, y, labels.getPixel(x, y - 1));
                        }
                        else if (y > 0 && x < labels.width && labels.getPixel(x + 1, y - 1) > 0) { // 右上
                            labels.setPixel(x, y, labels.getPixel(x + 1, y - 1));
                        }                        
                        else { // 4方向いずれも隣接していない時
                            labels.setPixel(x, y,++label); // 新しいラベル
                        }
                    }
                    //else {
                    //    labels.setPixel(x, y, 0); // ラベル無し
                    //}
                }
            }
            bmd.unlock(); // 表示を更新する
            
            _numericStepperLabelNum.maximum = label;
            _numericStepperLabelNum.minimum = 1;
            _numericStepperLabelNum.value = 1;
        }
        
        /* 選択したラベルの箇所を青く塗る。他は赤くする */
        public function showSelectedLabel(labelNum:int) {
            bmd.lock();
            var x:int, y:int;
            for (y = 0; y < bmd.height; y++){
                for (x = 0; x < bmd.width; x++) {
                    var currentLabel:int = labels.getPixel(x, y);
                    if (currentLabel == labelNum) {
                        bmd.setPixel(x, y, 0×000000FF); // 青
                    }
                    else if (currentLabel > 0) {
                        bmd.setPixel(x, y, 0×00FF0000); // 赤
                    }
                }
            }
            bmd.unlock();
        }    
    }
}

タグ: , , ,

コメントをどうぞ


track feed