2011年12月7日水曜日

FLEXのdataGridの配列の値を+=する件。

DataGridなるものがFLEXにある。
こんなコードを書く。
  1. datAr = new Array(  
  2.   {n:1,  type:0,  x:1.5,  y:2.5},  
  3.   {n:2,  type:1,  x:1.5,  y:2.5},  
  4.   {n:3,  type:2,  x:1.5,  y:2.5}  
  5. );  
  6. DG.dataProvider = datAr;  
ここに、datArはArrayであって、datAr[0].xは1.5という数値(Number)である。
しかし、
  1. datAr[0].x += 20;  
とすると、いつのまにやら、datAr[0].xがStringになっており、
datAr[0].x が、"1.520"
という文字列になっている。
  1. datAr[0].x = Number(datAr[0].x) + 20;  
とすれば、無事に、21.5になるのだが。
まぁ、こういうもんなのだろう。。

2011年12月1日木曜日

FLEXのObjectのdeleteする件の1

だいぶ更新をサボってしまった。。
さて、表題の件、かなりあれこれ迷った挙句、根本的にここらへんの仕組みを理解していなかったので、整理を含めて書いてみる。

まず、データが階層構造で存在している。(JSON)
これを、Objectに変換する。
これが、表示・編集する元データとなる。
しかし、これを表示するとなると、DisplayObjectにしなきゃいけない。
よって、それを包括したクラスを作成した。
こんな感じ。※実際にはこれをさらに派生させる。
  1. public class spBase extends UIComponent{  
  2. 。。。  
  3. public var obj:Object; // データの参照が入るよ。  
  4. 。。。  
  5. //実際には、このインスタンスに、以下のように設定  
  6. xxx.obj = maindata.a[0].b.c;  
要するに、
  1. "maindata":{  
  2.   "a":[  
  3.    {  
  4.    "b":{  
  5.     "c":{  
  6.        "dat1":1,  
  7.        "dat2":2,  
  8.        "dat3":3  
  9.      },  
  10.      "c2":{  
  11.        "cat1":1,  
  12.        "cat2":2,  
  13.        "cat3":3  
  14.      }      
  15.     }  
  16.    }  
  17.   ]  
  18. }  
って感じで。
で、何がやりたいかというと、xxxインスタンスを削除し、maindata.a[0].b.c;を無きものにしたいのだ。
xxxインスタンス自体は、xxx.parent.removeChildAt(zz);
で消せる。しかし、そんなことをやっても、maindata.a[0].b.cは、生きてる。
ここから、悪戦苦闘が始まるのだ。

テスト開始
  1. item:Object = new Object;  
  2. item.obj = mainData.a[0].b.c;  
で、デバッガで見た状況。
たしかに同じアドレスをさしている。

もちろん、
item.obj = {};
なんて書けば、こうなる。まぁ当然である。

でも、
trace(delete item.obj);
と書くと、こうなる。
【その1】

でも、
trace(delete mainData.a[0].b.c);
と書くと、こうなる。
【その2】

問題なのは、traceしてみると、両方ともtrueを返すことだ。
その1はいいのだが(いや、厳密には良くない気がするが。)、、、その2は、明らかに他が参照しているので、falseが返されるべきなんじゃ。。。。。
まぁどっちにしても、両方実行しないと消せないのである。

ってことは、、、参照だけもってても消せないのである。
ってことは、、、やりたいと思うことが、、できないわけである。

2011年9月8日木曜日

FLASHでGUIの4

HttpServer関連と、Loader関連をひとつのクラスにしようと思ったけど、
まぁ使い方を考えると、それぞれ別でもイイ気がしてきたので、別で。
基本はHttpServerと同じ。内部でLoaderクラスを呼ぶだけ。
Httpのときと同じように、ひとつずつ動作させる。
こんな感じで。
  1. // ------------------------------------------------------------------------------  
  2. function spLoadImage(){  
  3.   own = this;  
  4.   init();  
  5. }  
  6. // ------------------------------------------------------------------------------  
  7. public function ldInit(e:Event):void{  
  8.   trace(e);  
  9. }  
  10. // ------------------------------------------------------------------------------  
  11. public static function getEnum(n:int):String{  
  12.   switch(n){  
  13.     case eNotBitmap:    return  "Not Bitmap Resource";  
  14.     case eIOError:      return  "IO Error";  
  15.     case eSecurityError:  return  "Securit Error";  
  16.     default:        return  "Undifiend Error";  
  17.   }  
  18. }  
  19. // ------------------------------------------------------------------------------  
  20. private function ldComplete(e:Event):void{  
  21.   trace(e);  
  22.   if(loader.content is Bitmap){  
  23.     var lp:Object = loader.content;  //  var lp:Bitmapだとエラー  
  24.     var bit:Bitmap = new Bitmap(lp.bitmapData.clone());  
  25.     lp.bitmapData.dispose();  
  26.     okFunction(localVal,bit);  
  27.   }else{  
  28.     ngFunction(eNotBitmap,  getEnum(eNotBitmap));  
  29.   }  
  30.   nextGo();  
  31. }  
  32. // ------------------------------------------------------------------------------  
  33. private function ldIOError(e:IOErrorEvent):void{  
  34.   ngFunction(eIOError,e.text);  
  35.   nextGo();  
  36. }  
  37. // ------------------------------------------------------------------------------  
  38. private function nextGo():void{  
  39.   trace("--nextGo--");  
  40.   loader.contentLoaderInfo.removeEventListener(Event.INIT,        ldInit);  
  41.   loader.contentLoaderInfo.removeEventListener(Event.COMPLETE,      ldComplete);  
  42.   loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR,    ldIOError);  
  43.   bRun = false;  
  44.   execute();  
  45. }  
  46. // ------------------------------------------------------------------------------  
  47. private function init():void{  
  48.   uVar  = new URLVariables;  
  49.   datAr  = new Array;  
  50. }  
  51. // ------------------------------------------------------------------------------  
  52. public function setData(url:String,  comtype:uint,  okRes:Function,  ngRes:Function,  args:String,method:String="POST"):void{  
  53.   datAr.unshift(  
  54.     {  
  55.       "url":    url,  
  56.       "comtype":  comtype,  
  57.       "okFunc":  okRes,  
  58.       "ngFunc":  ngRes,  
  59.       "args":    args,  
  60.       "method":  method  
  61.     }  
  62.   );  
  63.   //  Array  //  pop()  最後を取り出して削除  //  unshift(... args):uint 最初に追加  
  64. }  
  65. // ------------------------------------------------------------------------------  
  66. public function execute():void{  
  67.   setTimeout(executeSub, tInterval);  
  68. }  
  69. // ------------------------------------------------------------------------------  
  70. private function executeSub():void{  
  71.   if(datAr.length < 1){  
  72.     //  END  
  73.   }else{  
  74.     if(bRun){  
  75.       setTimeout(executeSub, tInterval);  
  76.     }else{  
  77.       trace("☆executeSub "+datAr.length);  
  78.       bRun = true;  
  79.       var o:Object  = datAr.pop();  
  80.       loader = new Loader;  
  81.       loader.contentLoaderInfo.addEventListener(Event.INIT,        ldInit);  
  82.       loader.contentLoaderInfo.addEventListener(Event.COMPLETE,      ldComplete);  
  83.       loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR,  ldIOError);  
  84.       var UR:URLRequest    = new URLRequest(o.url);  
  85.       if(o.method == "GET")  UR.method = URLRequestMethod.GET;  
  86.       else          UR.method = URLRequestMethod.POST;  
  87.       uVar = new URLVariables;  //  何か設定することになるだろう。  
  88.       uVar.args = o.args;  
  89.       UR.data=uVar;        //    
  90.       okFunction  = o.okFunc;  
  91.       ngFunction  = o.ngFunc;  
  92.       localVal  = o.comtype;  
  93.       try{  
  94.         loader.load(UR);  
  95.       }  
  96.       catch (error:SecurityError){  //  err:Error  
  97.         ngFunction(eSecurityError,getEnum(eSecurityError));  
  98.       }  
  99.     }  
  100.   }  
  101. }  
  102. // ------------------------------------------------------------------------------  

2011年9月7日水曜日

FLASHでGUIの3

FLASHのGUIといっても、当然、サーバとのやりとりが必要なわけで。
そうすると、マルチタスクのイベントドリブンのような顔をしたActionScriptではあるけど、
正しくタイムシェアリングしてるわけでもなんでもないし、
サーバとの転送量が大きい場合(データが大きい画像とか)を考えると、
1つづつ実行できるようなシステムにしたいわけですね。
といったところで、画像一覧をゲットするようなことを考えて見る。

●httpのためのクラスを作る
【仕様】
→url、データのタイプ、パラメータ、callBack関数を複数指定して、
ひとつづつhttpリクエストをかける。
100コの画像を取ってくる場合でも、必ず、ひとつずつリクエストするものとする。

いろいろやって結果、スマートかどうかは別にして、、、
タイマを使うことになってしまった。
要するに、
実行中かどうかをフラグで判定して、判定中だったら、タイマをまた設定みたいなことを繰り返す。
ActionScriptにはSleepも無いことだし。
ちょっといい加減に書きなぐったSRCがこんな感じ。

なんとなくそれらしく動く。パラメータとかTEXT系じゃないときは、次に考えます。

  1. function spHttp(){  
  2.   own = this;  
  3.   init();  
  4. }  
  5. // ------------------------------------------------------------------------------  
  6. public function init():void{  
  7.   datAr  = new Array;  
  8. }  
  9. // ------------------------------------------------------------------------------  
  10. public function setData(url:String,  comtype:uint,  okRes:Function,  ngRes:Function,  method:String="POST",useProxy:Boolean=false):void{  
  11.   datAr.unshift(  
  12.           {  
  13.             "url":    url,  
  14.             "comtype":  comtype,  
  15.             "okFunc":  okRes,  
  16.             "ngFunc":  ngRes,  
  17.             "method":  method,  
  18.             "useProxy":  useProxy  
  19.           }  
  20.         );  
  21. }  
  22. // ------------------------------------------------------------------------------  
  23. public function execute(){  
  24.   setTimeout(executeSub, tInterval);  
  25. }  
  26. // ------------------------------------------------------------------------------  
  27. public function executeSub(){  
  28.   if(datAr.length < 1){  
  29.     //  END  
  30.   }else{  
  31.     if(bRun){  
  32.       setTimeout(executeSub, tInterval);  
  33.     }else{  
  34.       bRun = true;  
  35.       var o:Object  = datAr.pop();  
  36.       httpSV  = new HTTPService();  
  37.       httpSV.addEventListener(ResultEvent.RESULT,  okResult);  
  38.       httpSV.addEventListener(FaultEvent.FAULT,  ngResult);  
  39.       httpSV.resultFormat = "text";  //    
  40.       httpSV.url    = o.url;    //    
  41.       httpSV.method  = o.method;    //  httpSV.method = "POST";  
  42.       httpSV.useProxy  = o.useProxy;  //  httpSV.useProxy =false;  
  43.       uVar  = new URLVariables;  
  44.       uVar.decode("Giant=Baba");  
  45.       var at:AsyncToken = httpSV.send(uVar);  
  46.       at.id    = o.comtype;  
  47.       okFunction  = o.okFunc;  
  48.       ngFunction  = o.ngFunc;  
  49.     }  
  50.   }  
  51. }  
  52. // ------------------------------------------------------------------------------  
  53. public function okResult(event:ResultEvent):void{  
  54.   httpSV.removeEventListener(ResultEvent.RESULT,okResult);  
  55.   httpSV.removeEventListener(FaultEvent.FAULT,ngResult);  
  56.   okFunction(event);      //  本当の処理はこっちだよ  
  57.   bRun = false;  
  58.   execute();  
  59. }  
  60. // ------------------------------------------------------------------------------  
  61. public function ngResult(event:FaultEvent):void  
  62. {  
  63.   httpSV.removeEventListener(ResultEvent.RESULT,okResult);  
  64.   httpSV.removeEventListener(FaultEvent.FAULT,ngResult);  
  65.   ngFunction(event);      //  本当の処理はこっちだよ  
  66.   bRun = false;  
  67.   execute();  
  68. }  
  69. // ------------------------------------------------------------------------------  

2011年9月1日木曜日

FLASHでGUIの2



とりあえず、FLASHでのGUIのobjectの階層構造。(ver1)

<TOP> MXML
  <app> 固有クラス。アプリ制御(非GUI)
  <doc> 固有クラス。doc制御(非GUI)
  <menues> MXML
  <mainArea> MXML
    <Canvas>  :Base:UIComponent 
      <Layer>  :Base:UIComponent
        <Item>  :Base:UIComponent
        <Item>  :Base:UIComponent
        <Item>  :Base:UIComponent
        <Item>  :Base:UIComponent
      <Layer>  :Base:UIComponent
      <Layer id="last">  :Base:UIComponent
  <dialog> MXML

スケールを設定して拡縮するのは<Canvas>のみ。
<Layer id='last'>には、メッシュというかGRID表示させる。
BaseはUIComponentほぼそのままだが、基本的な機能だけをいれる。
マウスイベントをうけとるかどうかのon-offとか。

あとは、かならずTOPへの参照をできるようにして、appとかdocとかを適宜参照可能にする。

やっぱ、絵の出るプログラムは楽しいよね。




2011年8月30日火曜日

FLASHでGUIの1

FLASH(FLEX)でGUIの場合に、まず、それぞれのエンティティを、
どういう形で持つかというところから始める。
もちろん、objectとして持つので、グラフィックスをもてる形でもつのは当然として、
ページがあったり、レイヤーがあったりするので、そこらへんの階層をどう考えるかだね。
データ上の階層と表示やGUI上の階層は一致させる必要がないけど、
たいがい、一致させとかないと、バグる元。
ってことで、FLASH(FLEXではなく)でやってたときは、
movieClipかSpriteでなんでもかんでもやってたんだけど、
FLEXではSpriteはそのまま使えないから、UIComponentでやることになるのかな。
それが最良かどうかは、やってみないとわからないので、
とりあえず、それで、POLYや画像を表示させたり、編集したりとかしてみて判断しよう。
ということで、ポリを書いてみることにする。

順を追うと、、こんな感じでテスト。
●UIComponentを継承した基本クラスを作る。
●その基本クラスをExtendsした、item用のクラスを作る。
●itemを動的に生成して、その中のgraphicsにポリを入れてみる。
●mouseDown-Move-Upに対応させて移動させてみる。

ここで、随分前にちょっと書いた、mouseイベントを最下層で拾うクラスを仕込んでみる。
要するに、
★itemにMouseDonwがくる

★最下層Mouseイベント用クラスの、MouseDown/Up/Moveイベントを、
itemのpublic関数に持ってくるように設定する。
 ↓
★itemにMouseDonwがくる

★処理をしたあと、イベントの転送先を削除する

で、基本クラス。
  1. public class spBase extends UIComponent{  
  2.     public var mother:Object;  
  3.     //--------------------  
  4.     function spBase(){  
  5.   
  6.     }  
  7.     //--------------------  
  8.     public function init(f:Object):void{  
  9.         mother = f;  
  10.         this.addEventListener(Event.REMOVED_FROM_STAGE, removed);  
  11.         //-------------------  
  12.         //  MouseDown  
  13.         //-------------------  
  14.         var own:Object = this;  
  15.         this.addEventListener(MouseEvent.MOUSE_DOWN,  
  16.             function (e:MouseEvent):void{  
  17.                 mother.app.getKAM().setMAll(own.fd,own.fu,own.fm,own.fo);  
  18.             }  
  19.         );  
  20.     }  
  21.     //--------------------  
  22.     protected function fd(e:MouseEvent):void{  
  23.         trace("Down\n");  
  24.     }  
  25.     protected function fu(e:MouseEvent):void{  
  26.         trace("Up\n");  
  27.         mother.app.getKAM().setMClear();  
  28.     }  
  29.     protected function fm(e:MouseEvent):void{  
  30.         trace("Move ");  
  31.     }  
  32.     protected function fo(e:MouseEvent):void{  
  33.         trace("Over  ");  
  34.     }  
  35.     //--------------------  
  36.     //  like a destructer  
  37.     //--------------------  
  38.     private function removed(e:Event):void{  
  39.         removeEventListener(Event.REMOVED_FROM_STAGE, removed);  
  40.     }  
  41. }  

で、itemクラスの雛形。
  1. public class spItem extends soul.spBase{  
  2.     override protected function fd(e:MouseEvent):void{  
  3.         trace("spItem::Down\n");  
  4.     }  
  5.     override protected function fu(e:MouseEvent):void{  
  6.         trace("spItem::Up\n");  
  7.         mother.app.getKAM().setMAll(null,null,null,null);  
  8.     }  
  9.     override protected function fm(e:MouseEvent):void{  
  10.         trace("spItem::Move ");  
  11.     }  
  12.     override protected function fo(e:MouseEvent):void{  
  13.         trace("spItem::Over  ");  
  14.     }  
  15. }  

で、呼ぶ時。motherは、MXMLでのthisを渡している。。(-_-;)
  1. testobj = new soul.spItem();  
  2. testobj.init(mother);//mother:MXMLのthis  







2011年8月22日月曜日

FLASH再び。

長らく更新してませんでした。あまりに忙しく。。(-_-;)
ってことで、再会再開です。
とりあえず、、、ここ数ヶ月C++ばっかりだったので、FLASHを思い出すところから始めないと。

2011年5月29日日曜日

座標を変形させるのか?図形を変形させるのか?

グラフィックス全般のことなんですが、
【座標を変形させるのか?図形を変形させるのか?】
という問題があります。

一見、どっちでもよさそうな気がしますが、そうでもありません。
Adobe製品は、【座標】を変形させる方を選択しているため、

【文字フチをつけた文字フチ部分が文字ではなく図形となる】

という現象がおこります。
理由は、文字でフチ部分を定義してしまうと、座標を変形させているため、
文字のフチの線要素が、変形の影響を受けます。
当たり前なような気がしますが、線幅も影響を受けるため、
長体文字のフチの巾が、タテヨコでかわってしまう場合があるわけですね。

ちょっとわかりにくかったかもしれません。絵がないので。
ちょっと、、今はわかりやすい絵を描く気力がないので、
また今度書きます。

つまりこういうことですね。
普通にフチ付文字を書くと、座標の変換(偏倍)がないので、
こんな感じです。


これをこのまま横に偏倍するとこうなります。
まぁこれはこれでいいんですけど。。。
しかし、フチの幅を一定にしたち時もあるわけです。



そう、こういう風にしたい場合ですね。
これは、座標を変形させていると、線幅がタテヨコ変わるので、書けないんですね。



さらに、これはバグなのですが、
文字フチを文字で作成した(別プログラムでね。^^;)PDFを、イラレのCS5で読むと、
フチ文字部分が、正しい位置に配置されないというバグがあります。
CS4はわかりませんが、CS3では正しく読み込めていました。

フチをポリラインにしたPDFをイラレCS5で読み込んだとき。

フチを文字で書いたPDFをイラレで読み込んだ。
アメリカ→インドに変わって、、思想が変わったんですかね。。
いや、思想以前にバグだろこれ!




2011年5月21日土曜日

【詳解画像処理プログラミング】この本はあまりによくない。

この本なんですが、、、、
ぜんぜんダメでした。以前、読んだら書きますみたいに書いたのですが、
ダメです。買わないほうがいいでしょう。

(1)ターゲットがわからない。わかる人が読めばわかるけど、わからない人はわからないような書き方。だからといって、それほど高度な内容でもない。
(2)グラフィックスの本にしては、絵がすくなすぎる。同じ絵の使いまわしも多すぎ。内容に即した絵にもなっていない。
(3)ソースコードが美しくないし、遅すぎてそのままで使えるとも思えないし、説明の補足の役割がかろうじてあるかどうかってとこ。
(4)誤植が多すぎる。
(5)著者の思いが見えない。

以上の理由により、この本は、10段階評価2くらいの本ってことで。




2011年5月20日金曜日

2次元グラフィックライブラリを作る的なはなし(3)

単純に横方向へスキャンするときの欠点。

横方向へスキャンをして、面積比でアルファチャンネルを決定するだけでも、
垂直に近い辺に関しては、結構キレイに表示できます。

元の線は、こんな感じですかねー。

しかしこのやりかただけでは、大きな欠点がありますね。
それは、水平に近いせんの場合です。

こんな場合ですね。


の部分が、ガタガタです。ね 


本当はこうしたいところなのです

単純なスキャンだけではすまなそうですね。
はい、ダメですね。
じゃぁ、どうしましょうねー。
どこに書いてあったってわけじゃぁないんですけど、私はこう考えました。

ずいぶん前に紹介した絶版の本、
によると、1ピクセルを、さらに細かくスキャンする方法、
例としては、4回スキャンして足し合わせるようなことが紹介されていました。
しかしそれでは、グラデっぽく表示されるピクセルが4ドットを超える場合に、
やっぱり、多少ガタガタしてきますね。
だからといって、数十回やればいいかっていう、交点を求めるコストを考えると、
それはやりすぎです。

ということで、1ピクセルの中で交点を、2点求め、直線補完をします。

今度はピクセルの中間ではなく、1ピクセルのはじまり近くと終わり近くの
2つの位置でスキャンし、交点を2つ求めます。
それが、A,Bですね。

そうしたら、下図のように色わけした部分(青・黄)部分の面積比(↓図のCに対する面積比)で、
アルファチャンネルを決定します。


こんな程度でも、結構、イイ感じになります。

まぁ、これはこれで問題があるにはあるんですけどね。^^;^^;




2011年5月18日水曜日

2次元グラフィックライブラリを作る的なはなし(2)

前回は矩形だから簡単だった。
でも三角形とかだったらどうなる。。?

こういうのを考えると、ピクセルを考えなければ
↓ 

でも実際は1ピクセル以下は無理だから、
↓ 

でもアンチエイリアスというのをかけて
↓ 

これも実は、前回と同じように、スキャンするのです。

でも前回と違って、スキャンの交点に、小数点が入ってしまいますね。

交点に小数点以下がなければ、
って感じですが、ある場合はこうします。
↓ 

即ち、交点を求め(A)、そこにタテ線を入れて(B)
その、色を塗る面積の比率で、色の濃さを決定します。
実際には、上図では、白と紫の中間の色のようになりますが、
実際はアルファチャンネルにするべきです。
そうでないと、キャンバス色が白でないと、おかしな話になります。

つづく。。。

2011年5月17日火曜日

2次元グラフィックライブラリを作る的なはなし。(1)

2次元グラフィックライブラリを作る的なはなし。(1)
最初は、矩形を描く話でしょう。やっぱり。
矩形といっても、輪郭ではなく、塗りつぶしです。
輪郭の方が、難しいからです^^;ね。

あ、図の網目はピクセルですが、XYは、座標なので、
小数点があるくらいに思っときましょう。

こんな↓矩形を塗りつぶすと、

こんな↓風になりますよ。


ここではこれを、(3,3)-(7,3)-(7,8)-(3,8)の矩形、POLYLINEと呼んで見ます。
早い話、この矩形の中に位置するピクセルだけに色を塗るわけです。

これを、ヨコ方向に考え、↓の絵のごとくSCANしていきます。
要するに、水平方向のスキャンラインと矩形の交点を算定し、
交点と交点の間を塗りつぶします。


ということで、ロジックですが、、、
(3,3)-(7,3)-(7,8)-(3,8)
の、Y方向の最大最小値を調べると、
MIN:3 MAX:8とわかります。
よって、スキャンするライン(ヨコ線)としては、
y=3.5~7.5まで、1.0ずつ増分させていけばそれらしくなります。
なぜ、0.5を足すかというと、なんとなく中間だからなんですけどね。
要するに、左上のピクセルを塗ることは、
(0,0)-(1,0)-(1,1)-(0,1)の矩形を塗りつぶすという意味だと考えれば、
ピクセルの中心座標は、0,0ではなく、0.5,0.5となります。

これが正しいという話ではなく、考え方としてなんとなくそんな感じという風に思えばいいです。

つづく



2011年4月30日土曜日

画像をぼかす。。とは?3

ということで、【キレイにボカす】ということで、ガウス消去ガウスぼかしをいってみましょう。
まず、これ↓がガウス分布というやつです。
どうやってつくったかっていうと、

double ar = 1.0; // 1.0  2.0  2.8
for(int a = 0;a<100;a++){
    double aa = (double)a / 10.0;
    double gausu = exp( - (double)aa * aa / (2.0 * ar * ar ) );
    printf("gausu:%.6f\n",gausu);
}
こんなことを書いて、テキストファイルにリダイレクトして、openOfficeの表計算に貼って、
グラフ化して、でもこれだとグラフは右半分だけだから、
グラフィック系S/Wで対象な図形にしたわけです。

これがどう関係するかということですが、
前回は、上下左右のピクセルの色をとってきて、それを平均化することで、
ぼかしてたわけです。
これを、上下左右を**ピクセルづつとってきたときに、
遠い方のピクセルの影響度を少なくしようという方法です。
上の分布のように、中心を100%として、中心のピクセルの影響度を100%としたときの、
周囲のピクセルの影響度を減らしていくのです。

この場合も、前回と同様に、X方向にガウスぼかしをしたあと、
Y方向にガウスぼかしをすることによって、
上下左右を一度にぼかした結果と等価になるのです。
なぜかはここでは問題ではないのです。

ということで、やってみると、、、





やっぱりキレイにボケてます。
ちなみに前回のガウスぼかしじゃないやつ↓


ただし、欠点もないわけではなく、同じようなボケ精度(どのくらい判別できないか)
という点で考えると、ガウスぼかしの方が範囲を広くとらないと、
シャープになってしまいます。
よって範囲を広く取ると計算量が増えるわけですね。
もちろん、部分的に使うという使い方もできるので、
そうすれば計算量はたいして増えませんよね。

まぁでも、用途によってそこらへんは使い分ければいいわけなので、
この話はこのくらいで。

ちなみに、逆ガウスぼかしをしてみたところ、、
(※離れるほど重みを増やす)
そもそも何をやってるかわからなっちゃいましたね
↓↓↓↓↓






2011年4月29日金曜日

画像をぼかす。。とは?2


前回はモノクロだったので、カラーに適用するとこうなりますよ、、的な話。
もちろん、平均はR,G,Bと別々に平均をとりますよ。
αチャンネルはどうしましょうかね。まぁとりあえずは元のままでいいでしょう。
(平均を取らずにもとのピクセルのα値をそのまま使用する)
但し、正しくはというか、画像の合成という話題になったりすると、
αチャンネルをもつ画像同士の合成なんかを考えなきゃならないので、
そのとき考えましょう。
このへんのことは、正しく処理されていないS/Wをときどき見かけますんで、
っていうか、自分でも何度もバグを出しましたけどね^^;^^;^^^;

ってことで、あとはサンプルの画像のみで。







↑これがガウスぼかし(半径15)
カラーですると、単純に前後左右で矩形で平均をとったものと
歴然の差がでますね。^^;^^;^^;
なんか、、【キレイにボケてる】感があります。

うん。しょうがない。次回はガウスぼかしだな^^;^^;


画像をぼかす。。とは?

画像をぼかす。。って、ちょこちょこ書いてたわけですが、
技術的には、非常に簡単な考え方です。

下図の黒い部分がドット(ピクセル)だとすると、
その周辺を含めた平均を出し、その値に変換してしまうのです。
要するに、赤いピクセルに着目し(下図の)、
その周辺、たとえば前後左右を1ピクセルずつ考慮すると、
9ピクセルの矩形が考えられます(下図の)。
これの平均を出して、変換後のピクセルの色にしてしまうだけです。
この画像を前後左右1ピクセルを考慮すると、
こうなります。


どうようにして、こんな画像を用意して、
影響範囲を前後左右1ピクセルの3*3=9ドットの平均すると
↓ 
影響範囲を前後左右2ピクセルの5*5=25ドットの平均すると
↓  

影響範囲を前後左右3ピクセルの7*7=49ドットの平均すると
↓  
影響範囲を前後左右4ピクセルの9*9=81ドットの平均すると
↓   


影響範囲を前後左右7ピクセルの15*15=225ドットの平均すると
↓    

影響範囲を前後左右15ピクセルの31*31=961ドットの平均すると
↓   


っとこれでわかるように、演算量は、2乗に比例するような気もするのですが、
実は、タテと横を別々に行っており、最初にヨコでぼかした画像を生成し、
それをさらにタテにぼかして画像を生成します。
よって、計算量は、2乗ではなく、2Nですかね。。

間単に、【平均】なんて書いてしまいましたけど、平均のとりかたに、
重みをつけたりすると、微妙に結果がかわります。

そこらへんは、、、まぁ、いろいろ調べてみましょう^^;^^;
その中のひとつに、【ガウスぼかし】なるものがあります。
まぁたいしたものでもないのですが、たまにはSRCを乗せると。。
二重のLOOPを2回まわしてるだけですね。^^;
  1. int minusv = (haba - 1) / 2;  
  2.     for(int yy = 0;yy<hh;yy++){  
  3.         for(int xx = 0;xx<ww;xx++){  
  4.             for(int z=0;z<haba;z++){  
  5.                 int idxx = xx + z - minusv;  
  6.                 int idxy = yy;// + z - 2;  
  7.                 if(getPixelIndex(G,idxx,idxy)){  
  8.                     uc[z] = G.GetPixelsDirect3(idxx,idxy);  
  9.                 }  
  10.             }  
  11.             unsigned int ucc = getBock5(uc,haba);  
  12.             GO.SetPixels32(xx,yy,ucc);  
  13.         }  
  14.     }  
  15.     for(int yy = 0;yy<hh;yy++){  
  16.         for(int xx = 0;xx<ww;xx++){  
  17.             for(int z=0;z<haba;z++){  
  18.                 int idxx = xx;// + z - 2;  
  19.                 int idxy = yy + z - minusv;  
  20.                 if(getPixelIndex(GO,idxx,idxy)){  
  21.                     uc[z] = GO.GetPixelsDirect3(idxx,idxy);  
  22.                 }  
  23.             }  
  24.             unsigned int ucc = getBock5(uc,haba);  
  25.             G.SetPixels32(xx,yy,ucc);  
  26.         }  
  27.     }