| 
 | 
 
 
 
 
 |  | 
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命令で操作?
 といった変なアイデアぐらいしか思い浮かびません…うまい方法があればいいのですが…
 
 | 
 
 
 
 |  | 
2011/8/18(Thu) 00:07:08|NO.40675 
要するにcircleで描かれた円を数えたいんだったら、時間かかるけど単に適当なサイズの円とピッチリ合うか?を調べればいい
 
 第一HSPの描画命令は直接画面操作するから、描画時にIDとかをつけておかないと
 そういった操作は非常に難しい
 質問者が変に思い浮かんだという4つのアイデアのどれも推奨できないし、
 まして今書いた手法もシステムにものすごく負担がかかるから絶対にやらないほうが良い
 
 | 
 
 
 
 
 |  | 
2011/8/18(Thu) 00:20:27|NO.40677 
あ、ついでに言っておくけどコロニーカウンターはちゃんとコロニーが実際にどのように表示されるかの
 パターンを記憶してるからちゃんと動作するのであって、
 しかもコロニーの見かけ上のサイズがあまり変わらないから数えられる
 
 しかし
 無作為にサイズばらばらにびっちり描画された円は輪郭がはっきりしているから
 まず不可能に近いとは思う。
 
 ま、頑張れ。工夫次第だ。
 
 | 
 
 
 |  | 
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様の考え方が優秀過ぎて、長々としたスクリプトが恥晒しに……
 まあ、世の中には自分より遥かに優れた人達が沢山いるという事を再確認できただけでも大儲けです。
 
 | 
 
 
 |  | 
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
|  
 |  | 
 
 
 |  | 
2011/8/21(Sun) 16:32:31|NO.40750 
多種のノイズを含む画像から、任意の物体を認識するのは相当難しい問題です。4大卒業レベルで、動画像処理を専門的に研究していないと、まず話しについていけないですね。
 プログラミングが出来るだけでは、解ける問題ではありません。
 まずは、図書館や本屋へ行って、専門的知識を養う。
 慣れてきたら、ググッてでも論文を何本か読む、話はそれからですね。
 意を決して質問されたようですが、きついこと言ってごめなさい。
 
 | 
 
 
 |  | 
2011/8/25(Thu) 14:18:35|NO.40844 
いつのまにかレスがたくさんついていて感動しました!おかげさまでとても勉強になりました。書き込んでいただいたみなさん,どうもありがとうございました!
 
 | 
 
 
 |