HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2011
0817
よし画像内の円の数をカウントするのが難しい10解決


よし

リンク

2011/8/17(Wed) 23:41:50|NO.40674

意を決して質問させていただきます.

たとえば
screen 0,640,480:cls:color 0,0,0:n=rnd(30)
repeat n
x=rnd(640): y=rnd(480)
circle x-8,y-8,x+8,y+8
loop
で描かれたような画像(白画面にいくつか黒円が描かれた画像)があったとして,
この画像から逆に黒円の「個数」を数え上げるにはどうしたらいいか悩んでいます.

将来的には,円のサイズが様々であっても,あるいは他に図形があっても数えられるようにしたり,円がある程度重なっていても数えられるようにしたい(だから黒い画素数を数えて円の面積で割る方法は不適),さらに欲を言えばある画像から任意の画像パターンの数を数えられるようにできたらいいなと思っているのですが,
まずはその前にどのような戦略でプログラムを組めばよいのか見当がつかないので,御指南いただければ幸いです.

たとえば,僕が思いついたものとしては,
1. 画像をモザイク状にして数える?
2. hspcvの顔認識プログラムで,顔データが学習されたXMLファイルを円用に改造する?
3. hsp命令のcvmatchを応用する?
4. 何かそういうカウント機能がついたプログラムをexec命令で操作?
といった変なアイデアぐらいしか思い浮かびません…うまい方法があればいいのですが…



この記事に返信する


backdrop

リンク

2011/8/18(Thu) 00:07:08|NO.40675

要するにcircleで描かれた円を数えたいんだったら、
時間かかるけど単に適当なサイズの円とピッチリ合うか?を調べればいい

第一HSPの描画命令は直接画面操作するから、描画時にIDとかをつけておかないと
そういった操作は非常に難しい
質問者が変に思い浮かんだという4つのアイデアのどれも推奨できないし、
まして今書いた手法もシステムにものすごく負担がかかるから絶対にやらないほうが良い



よし

リンク

2011/8/18(Thu) 00:12:46|NO.40676

おっしゃるとおりですね.プログラムで描いた画像を解析するというのであれば,描画時にIDをつけるのが最もよいですし,どの方法もすごく時間がかかりそうなつらい方法です…

将来的な目標として,下記のコロニーカウンターのようなものを作れたら素敵だな,と思っています.


http://nition.com/download/colonycounter.htm



backdrop

リンク

2011/8/18(Thu) 00:20:27|NO.40677

あ、ついでに言っておくけど
コロニーカウンターはちゃんとコロニーが実際にどのように表示されるかの
パターンを記憶してるからちゃんと動作するのであって、
しかもコロニーの見かけ上のサイズがあまり変わらないから数えられる

しかし
無作為にサイズばらばらにびっちり描画された円は輪郭がはっきりしているから
まず不可能に近いとは思う。

ま、頑張れ。工夫次第だ。



774

リンク

2011/8/18(Thu) 01:20:23|NO.40678

たいした知識も無いくせに「まず不可能に近いとは思う」と
断言してる人が居るので、簡単な考え方だけ。

・エッジ検出
 (基準点と一つ隣の RGB 値を調べ、しきい値を越えて RGB 値が変化したらエッジ点と判断)
・検出されたエッジ点の座標を固まりに分け ID を付ける
 (座標と座標の距離が 3 以内なら同じ固まりと判断)
・ID ごとに
  ・固まりの縦、横のサイズを調べる ※1
  ・固まりの中心座標を調べる
  ・固まりの中にエッジ点がどれだけ占めるか調べ、特定の % 以上なら
   その固まりは網点やしましまの可能性が高いので、廃棄。
   逆に固まりが1や2コのエッジ点だけなら、それはノイズなので同じように廃棄。
・ID ごとに円かどうかの判断
  ・太さ3のラインの円、半径は ※1 に入る大きさから徐々に -1 する ※2
  ・円を 45 度ずつ、8コに分解し、例えばその中で6コでエッジ点を
   含んだら、それを円と判断

※2 の処理では速度アップのためにいちいち円を描画して重なるかどうかを
判断するのではなく、例えば「線の太さ3、半径20」の円の座標のペアを
配列に保存しておく。

上記であげたいくつかの具体的な数値は、いろいろと振ってみて
計算量や検出率を評価してみて下さい。



木村

リンク

2011/8/18(Thu) 01:26:15|NO.40679

 とりあえず√2≒0.71を利用すれば勝機はあるはず。以下は一例

#define SEARCH_SCREEN 0 #define DATA_SCREEN 1 #define BLACK_BUFFER 2 #define WHITE_BUFFER 3 //日本語部分は命令名兼一筆 //細かい関数に分かれているのは当方の癖 //兼、説明も兼ねてる為 //行き先分かんなかったらF11、以上 実験用のスクリーンを作成 SEARCH_SCREEN その他ウィンドウを作成 repeat マウス座標取得 mx, my 黒白領域取得 データの描画処理 DATA_SCREEN, mx, my wait 10 loop end #deffunc データの描画処理 int _scr, int _mx, int _my \ , local _black, local _white gsel _scr redraw 0 color 255, 255, 255 boxf 走査領域提示 0, 0, _mx, _my 黒塗領域提示 64, 0 白塗領域提示 64, 80 _black = 黒塗り率() _white = 白塗り率() color pos 0, 128 mes strf("黒塗り率=%d%",int(_black*100)) mes strf("白塗り率=%d%",int(_white*100)) if _black*_white > 0.85 { color 255 mes "恐らく○です" } redraw 1 return #deffunc その他ウィンドウを作成 screen DATA_SCREEN, 200, 200 buffer BLACK_BUFFER, 14, 14 buffer WHITE_BUFFER, 12, 3 return #deffunc 実験用のスクリーンを作成 int _scr, local _n \ , local _x, local _y screen _scr, 640, 480 _n = 10+rnd(30) repeat _n _x = rnd(640) _y = rnd(480) circle _x-10, _y-10, _x+10, _y+10 loop return #deffunc マウス座標取得 var _mx, var _my gsel SEARCH_SCREEN _mx = mousex _my = mousey return #deffunc 黒白領域取得 gsel BLACK_BUFFER gcopy SEARCH_SCREEN, mx-7, my-7, 14, 14 gsel 3 pos 0, 0 gcopy SEARCH_SCREEN, mx-10, my-10, 3, 3 pos 3, 0 gcopy SEARCH_SCREEN, mx+7, my-10, 3, 3 pos 6, 0 gcopy SEARCH_SCREEN, mx-10, my+7, 3, 3 pos 9, 0 gcopy SEARCH_SCREEN, mx+7, my+7, 3, 3 return #deffunc 黒塗領域提示 int _px, int _py color 255, 192, 0 boxf _px, _py, _px+63, _py+79 pos _px+4, _py+20 gzoom 56, 56, BLACK_BUFFER, 0, 0, 14, 14 color pos _px, _py mes "黒塗領域" return #deffunc 白塗領域提示 int _px, int _py color 192, 255, 0 boxf _px, _py, _px+63, _py+31 pos _px+8, _py+18 gzoom 48, 12, 3, 0, 0, 12, 3 color pos _px, _py mes "白塗領域" return #deffunc 走査領域提示 int _px, int _py, int _mx, int _my color 255, 255, 0 boxf _px, _py, _px+63, _py+111 pos _px+2, _py+18 gzoom 60, 60, SEARCH_SCREEN, _mx-10, _my-10, 20, 20 color pos _px, _py mes "走査領域" pos _px, _py+79 mes "X="+_mx pos _px, _py+95 mes "Y="+_my return #defcfunc 黒塗り率 local _vram, local _x, local _y \ , local _sel, local _count _sel = ginfo_sel gsel BLACK_BUFFER mref _vram, 66 for _y, 0, 14 for _x, 0, 14 if peek(_vram,_y*44+_x*3) = 0 : _count+ next next gsel _sel return double(_count)/14/14 #defcfunc 白塗り率 local _vram, local _x, local _y \ , local _sel, local _count _sel = ginfo_sel gsel 3 mref _vram, 66 for _y, 0, 3 for _x, 0, 12 if peek(_vram,_y*36+_x*3) = 255 : _count+ next next gsel _sel return double(_count)/12/3
 おやすみなさい。



木村

リンク

2011/8/18(Thu) 01:41:43|NO.40680

※上記プログラムの補足
 大きい方のスクリーンに黒丸がぽつぽつとあるはずです。黒丸の中心辺りにカーソルを近付けてやると、小さい方のスクリーンに『おそらく○です』なる文字が表示されるはずです。

 円の性質上、四隅の半径の3割程度の長さの正方形の領域は真っ白に、中央の半径の7割程度の正方形の領域は真っ黒になります。
 この真っ白と真っ黒の部分を抽出して、黒塗り率と白塗り率を算出し、その値がある一定程度を超えたら丸だろうと判断する仕組みです。

 ……しかし774様の考え方が優秀過ぎて、長々としたスクリプトが恥晒しに……
 まあ、世の中には自分より遥かに優れた人達が沢山いるという事を再確認できただけでも大儲けです。



f(玩具配布中)

リンク

2011/8/18(Thu) 08:50:07|NO.40681

所謂画像認識/画像処理は、はまり込めば趣味的に楽しいのだが
単純に今すぐ実用的な物が欲しいだけなら

Cognex
http://www.cognex.com/main.aspx?langtype=1041



In-Sight Explorer
http://www.cognex.com/Support/InSight/Software.aspx
>2011/04/06 In-Sight Explorer 4.5.0 ソフトウェア (In-Sight Explorer本体のみ) 392.9 MB

をDLするのが良かろう。


これのエミュレーションモードを薦める。

実際に世間の工場などで製品検査に使われている画像処理機器の管理用ソフトなのだが、
画像を対象に実機と同じ動作をするエミュレーションモードがある。
実機がないと「結果を出力」する事は出来ないが、画面上では結果を確認できる。


DLしただけでは、ネットワーク内に「In-Sight本体」が無いと
「エミュレーション機能」にロックが掛かかるが、


In-Sight キージェネレータ
http://www.cognex.com/Support/ISKeyGenerator.aspx

ここに、
In-Sight Explorerの「システム->オプション->エミュレーション」から
「オフラインプログラミングの問い合わせ番号」をコピペ入力して送ると
解除コードが発行される。

(In-Sight)プログラム的には、
・画像から目標色部分を抽出した画像を作成(色フィルタ等)
・できた画像からブロブ(塊)の数を数える(ブロブツール等)
->複数の円が重なっている場合は1つとして数えられる

か、

・基本形状を登録し、画面上に幾つあるか計測する(FindPaternツール等)
->形状が登録時と大幅に違う/はっきりしない場合はカウントできない

こんなもんか。



てれてれ

リンク

2011/8/18(Thu) 15:42:48|NO.40683

これから用事で時間が無いので、説明を端折らせて下さい。
このスクリプトでは、面倒だったので比較的扱いやすいpgetを使っていますが、
mrefを使ってウィンドウ内画像データのカラー情報をチェックしていった方が高速な処理が可能です。

円の判定も適当です。

円が重なったときの処理を考える時間もありませんでしたので、
あとはこの掲示板に居られる上級者の方々に任せます。

スクリプトが汚いのは仕様です。

バグがあるかもしれません。

行ってきます。


//円を表示 randomize screen 0,640,480:cls:color 0,0,0:n=rnd(30)+10 repeat n x=rnd(610): y=rnd(430) color rnd(255),rnd(255),rnd(255) circle x+rnd(5),y+rnd(5),x+rnd(15)+17,y+rnd(15)+17 loop notesel buf ;ログ用 SColor = 255,255,255 SMx = 640 SMy = 480 color:pos 0,0 dim CPx,100 : dim CPy,100 ;検出した円の位置 dim CSx,100 : dim CSy,100 ;検出した円の大きさ repeat SMx title ""+cnt+"/"+(SMx-1) cn1 = cnt repeat SMy cn2 = cnt await 0 pget cn1,cn2 if ginfo_r != SColor(0) or ginfo_g != SColor(1) or ginfo_b != Scolor(2){ //同じ円を2回以上検出しないように BCid=-1 repeat Cid if cn1>=CPx(cnt) and cn1<=CPx(cnt)+CSx(cnt) and cn2>=CPy(cnt) and cn2<=CPy(cnt)+CSy(cnt){ BCid=cnt break } loop if BCid!=-1:continue limit(CPy(BCid)+CSy(BCid)+1,0,SMy-1) NColor = ginfo_r,ginfo_g,ginfo_b;検出した円の色を記録 repeat ,1 pget cn1+cnt,cn2;円の最も長い横(x)の長さを調べるために色チェック if ginfo_r != NColor(0) or ginfo_g != NColor(1) or ginfo_b != Ncolor(2){ NCid=Cid;現在の円のIDを記録 CSx(Cid) = cnt repeat ,1 pget cn1,cn2+cnt if ginfo_r != NColor(0) or ginfo_g != NColor(1) or ginfo_b != Ncolor(2){ cn4=cnt;円の一番左のドットの縦(y)の長さを記録 break } loop repeat ,1 pget cn1+CSx(Cid)/2,cn2+(cn4-1)/2-cnt;円の最も長い縦(y)の長さを調べるために色チェック if ginfo_r != NColor(0) or ginfo_g != NColor(1) or ginfo_b != Ncolor(2){ CSy(Cid) = cnt*2 break } loop CPx(Cid) = cn1 ;円の左端のx座標を代入 CPy(Cid) = cn2+(cn4-1)/2-CSy(Cid)/2 ;円の左端のy座標を代入 if CSx(Cid)<=10 or CSy(Cid)<=10 : NG = 1 : break ;円の縦と横の長さが正常値であるかチェック NG=0 dim NC,2 repeat CSx(Cid) cn5=cnt BF = 0 repeat CSy(Cid)/2 cn6=cnt pget CPx(Cid)+cn5,CPy(Cid)+cn6;円の形を調べるために色チェック if ginfo_r = NColor(0) and ginfo_g = NColor(1) and ginfo_b = Ncolor(2){ //円の形が正常かどうかチェック if BF = 1 and BNC(0) >= NC(0) : NG=1 if BF = 0 and BNC(0) <= NC(0) : BF=1 BNC(0)=NC(0) : NC(0)=cnt ;円の形のチェック用 break } loop if NG=1:break repeat CSy(Cid)/2 cn6=CSy(Cid)-cnt pget CPx(Cid)+cn5,CPy(Cid)+cn6 if ginfo_r = NColor(0) and ginfo_g = NColor(1) and ginfo_b = Ncolor(2){ BNC(1)=NC(1) : NC(1)=cnt;円の形のチェック用 break } loop if abs(NC(0)-NC(1))>=3 : NG = 1 ;円の形が正常かどうかチェック if NG=1:break loop if NG=0{ noteadd "ID:"+Cid+" POS("+CPx(Cid)+","+CPy(Cid)+") SIZE("+CSx(Cid)+","+CSy(Cid)+")" ;ログに記録 Cid++ } break } loop continue limit(CPy(NCid)+CSy(NCid)+1,0,479) } loop loop screen 1,,,8 mesbox buf,640,480 ;ログ表示 gsel 0,1 repeat Cid //描写 redraw 0 color 255 circle CPx(cnt),CPy(cnt),CPx(cnt)+CSx(cnt),CPy(cnt)+CSy(cnt) color line CPx(cnt)+CSx(cnt)/2,CPy(cnt),CPx(cnt)+CSx(cnt)/2,CPy(Cnt)+CSy(cnt)-1 line CPx(cnt),CPy(cnt)+CSy(cnt)/2,CPx(cnt)+CSx(cnt)-1,CPy(cnt)+CSy(cnt)/2 pos CPx(cnt)+CSx(cnt),CPy(cnt) : mes "ID:"+cnt redraw 1 wait 10 ;1つずつ描写 loop



hps

リンク

2011/8/21(Sun) 16:32:31|NO.40750

多種のノイズを含む画像から、任意の物体を認識するのは相当難しい問題です。
4大卒業レベルで、動画像処理を専門的に研究していないと、まず話しについていけないですね。
プログラミングが出来るだけでは、解ける問題ではありません。
まずは、図書館や本屋へ行って、専門的知識を養う。
慣れてきたら、ググッてでも論文を何本か読む、話はそれからですね。
意を決して質問されたようですが、きついこと言ってごめなさい。



よし

リンク

2011/8/25(Thu) 14:18:35|NO.40844

いつのまにかレスがたくさんついていて感動しました!
おかげさまでとても勉強になりました。書き込んでいただいたみなさん,どうもありがとうございました!



ONION software Copyright 1997-2023(c) All rights reserved.