ポク太郎です。
できるだけ画像認識は使わないのが定石。が、やむを得ず必要になることが。
あいまいな画像検索用の関数CHKIMGXが配布されていますが、筆者はまだ試しておりません。
その前に、標準の画像認識で失敗する理由を確実につかもうと思い、関数を作成しました。
画像認識ができない理由
今、筆者から見えている“画像認識できない”理由は下記です。
※ここではUWSCに比較させるための画像をリファレンス画像と呼んでいます。
※ここではUWSCに比較させるための画像をリファレンス画像と呼んでいます。
1 リファレンス画像と異なるものを検索 | |
1-1 リファレンス画像をBMPで取得していない
PNGやJPEGなど非可逆圧縮で保存すると元の画像を劣化させてしまうのでBMP(ビットマップ)で保存する必要があります。
|
|
1-2 リファレンス画像を保存する際加工されてしまった
Alt+PrintScreenキーで画像編集ソフトに貼り付けて保存する場合に加工されてしまうものがある。筆者が経験したのはWin10標準アプリの「Paintペイント」。
|
|
1-3 グラボによりγカーブが掛けられ色味が異なる
画像を採取したPCと別環境ではグラボが異なるので、別のγカーブが当てられる。初期状態が同じベンダ(nVidia、Radeonなど)同士なら大抵は認識できるが完全には難。
|
|
1-4 対象のソフトがアップデートされ異なる表示になってしまった
特にブラウザのような頻繁にアップデートされるソフトではよく遭遇します。
|
|
2 検索範囲がずれている | |
2-1 検索範囲を勘違いしている
処理速度を上げようと画像検索の範囲を絞ろうとした場合などによく陥ります。
|
通常の画像認識でどこまで確実にできるかを確認するため、デバッグ機能付きの関数を作成します。
※上記の1-3、1-4は回避できませんが、他は回避可能になるので追加機能が必要か確かめることができます。CHKIMGXを使用した場合に1-3、1-4が完全対応できるかどうかは筆者はまだわかっておりません。
スクリーンショット画像をUWSC自身に取得させる
Alt+PrintScreenキーで画像を取得していると上で挙げた操作ミスなどを招いてしまう&面倒なので、画像を取得する機能を関数として作成しました。
●2つの選択ボタン(“取得”と“5秒後に取得”)を持つダイアログを表示→選択に従い、ソースコードのあるディレクトリにファイル名“画像_000X.bmp”で画像保存。
●関数を抜ける条件はダイアログの閉じるボタン(Xボタン)が押されたとき。
※関数の形にしましたが、独立した画像取得アプリにしておいてもいいかもしれません。
FUNCTION get_pic(id)
cancel=0
WHILE (cancel=0)
SELECT SLCTBOX(slct_btn,0,1,400,"画像を取得します。","取得","5秒後に取得")
CASE -1
cancel=1
CASE 1
wait=0
CASE 2
wait=1
SELEND
IF cancel=0
PRINT "準備しています。"
IF id<>-1
IF STATUS(id,ST_ICON)//最小化状態かどうか
CTRLWIN(id,NORMAL)//通常表示に
ENDIF
IF !STATUS(id,ST_ACTIVE)//非アクティブかどうか
CTRLWIN(id,ACTIVATE)//アクティブに
ENDIF
ELSE
PRINT "アプリが見つからないので全体画像を取得します。"
ENDIF
IF wait=1
FOR i=5 TO 1 step -1
PRINT i+"秒後に取得します。"
SLEEP(1)
NEXT
ENDIF
n=0
WHILE (0=0)
path=GET_CUR_DIR+"\画像_"+REPLACE(FORMAT(n,4)," ","0")+".bmp"
IF FOPEN(path,F_EXISTS)
n=n+1
ELSE
IF id<>-1
SAVEIMG(path,id)
ELSE
SAVEIMG(path)
ENDIF
PRINT "画像を取得しました。"
break
ENDIF
SLEEP(0.1)
WEND
ENDIF
SLEEP(0.05)
WEND
RESULT=1
FEND
1,50行目 | 1 50 |
FUNCTION get_pic(id) FEND |
get_pic(id)関数宣言:画像をUWSC自身に取得させる関数。 引数id:アプリIDを渡します。画面全体を取得する場合は-1指定。 |
||
2~3,47~48行目 | 2 3 47 48 |
cancel=0 WHILE (cancel=0) SLEEP(0.05) WEND |
変数cancel:下で表示させるダイアログの閉じるボタンが押された場合に1になる変数。 閉じるボタンが押されるまで、4~46行目の間をループします。 |
||
4~11行目 | 4 5 6 7 8 9 10 11 |
SELECT SLCTBOX(slct_btn,0,1,400,“画像を取得します。“,“取得“,“5秒後に取得“) CASE –1 cancel=1 CASE 1 wait=0 CASE 2 wait=1 SELEND |
セレクトボックスを表示します。 case -1 ⇒ 閉じるボタンが押された場合の処理 case 1 ⇒ 取得ボタンが押された場合の処理 case 2 ⇒ 5秒後に取得ボタンが押された場合の処理(取得したい状態を準備するための待ち時間として5秒) 変数wait:画像取得までに5秒間の待ち時間を入れるかどうかを記憶します。 |
||
12,46行目 | 12 46 |
IF cancel=0 ENDIF |
閉じるボタンが押されていない場合のみ、13~45行目を実行。 | ||
14~23行目 | 14 15 16 17 18 19 20 21 22 23 |
IF id<>–1 IF STATUS(id,ST_ICON)//最小化状態かどうか CTRLWIN(id,NORMAL)//通常表示に ENDIF IF !STATUS(id,ST_ACTIVE)//非アクティブかどうか CTRLWIN(id,ACTIVATE)//アクティブに ENDIF ELSE PRINT “アプリが見つからないので全体画像を取得します。“ ENDIF |
引数idが-1ではないとき(対象が画面全体ではないとき)、 ウィンドウが最小化状態なら ⇒ 通常表示にする ウィンドウが非アクティブ状態なら ⇒ アクティブにする |
||
24~29行目 | 24 25 26 27 28 29 |
IF wait=1 FOR i=5 TO 1 step –1 PRINT i+“秒後に取得します。“ SLEEP(1) NEXT ENDIF |
上記のセレクトボックスで“5秒後に取得”ボタンが押された場合(変数waitが1)に実行。1秒ごとのカウントダウンを表示していきます。 | ||
30~45行目 | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
n=0 WHILE (0=0) path=GET_CUR_DIR+“\画像_“+REPLACE(FORMAT(n,4),“ “,“0“)+“.bmp“ IF FOPEN(path,F_EXISTS) n=n+1 ELSE IF id<>–1 SAVEIMG(path,id) ELSE SAVEIMG(path) ENDIF PRINT “画像を取得しました。“ break ENDIF SLEEP(0.1) WEND |
ファイル名を“画像_000x.bmp”として保存していきますが、空きファイル名を調べるためのルーチン。被らないファイル名ができるまでループを回り続けます。保存完了するとループを抜け関数を抜けます。 32行目 :変数pathにファイル名を作り出します。 33行目 :作成したファイル名のものが存在しているかどうかを調べ、 (存在する) 変数nをインクリメントして再度ループ先頭へ (存在しない) 画像を保存(引数idにより分岐)、ループ抜ける します。 |
画像の検索範囲をカーソルで描く
以前こちら(見つけた指定画像の中心座標を返す関数)で作成した関数にデバッグの引数を追加→検索範囲の外周に沿ってマウスカーソル移動させ、すぐわかるよう機能追加。
トラブルがあった際に、呼び出し側のソースをデバッグ用に変更して(デバッグ引数1を渡す)すぐに検索範囲を確認できるようにしておきます。
FUNCTION imgxyd(m,pic,db)
DIM xy[1]
wh=bmp(pic)
IF db=1
FUKIDASI(SX1+","+SY1,SX1,SY1,0,,,$000000,$00CCEE)
FOR i=SX1 TO SX2 step (SX2-SX1)/100
MMV(i,SY1)
SLEEP(0.001)
NEXT
FUKIDASI(SX2+","+SY1,SX2,SY1,0,,,$000000,$00CCEE)
FOR j=SY1 TO SY2 step (SY2-SY1)/100
MMV(SX2,j)
SLEEP(0.001)
NEXT
FUKIDASI(SX2+","+SY2,SX2,SY2,0,,,$000000,$00CCEE)
FOR i=SX2 TO SX1 step (SX1-SX2)/100
MMV(i,SY2)
SLEEP(0.001)
NEXT
FUKIDASI(SX1+","+SY2,SX1,SY2,0,,,$000000,$00CCEE)
FOR j=SY2 TO SY1 step (SY1-SY2)/100
MMV(SX1,j)
SLEEP(0.001)
NEXT
ENDIF
SELECT m
CASE 1
haba="IMG_MSK_BGR1"
CASE 2
haba="IMG_MSK_BGR2"
CASE 3
haba="IMG_MSK_BGR3"
CASE 4
haba="IMG_MSK_BGR4"
DEFAULT
haba="IMG_MSK_BGR4"
SELEND
IF CHKIMG(pic,,SX1,SY1,SX2,SY2,,haba)
xy[0]=G_IMG_X+wh[0]/2
xy[1]=G_IMG_Y+wh[1]/2
FUKIDASI(xy[0]+","+xy[1],xy[0],xy[1],0,,,$FFFFFF,$008800)
ELSE
xy[0]=0
xy[1]=0
FUKIDASI("画像が見つかりません。",0,0,0,,,$FFFFFF,$008800)
ENDIF
RESULT=SLICE(xy,0,LENGTH(xy)-1)
FEND
1,48行目 | 1 48 |
FUNCTION imgxyd(m,pic,db) FEND |
imgxyd(m,pic,db)関数宣言:表示された指定画像の中心座標を返す関数。(デバッグ機能付) 引数m:色幅を1~4で指定します。 引数pic:リファレンス画像のパスを渡します。 引数db:デバッグのオンオフ指定。デバッグ時には1を渡す。 【ご注意】この関数を使用する際には、グローバル変数として以下を宣言、代入しておく必要があります。 |
||
2,3行目 | 2 3 |
DIM xy[1] wh=bmp(pic) |
配列変数の定義とBMP画像の幅と高さを取得。 bmp()関数はこちら(BMP画像の幅と高さを得る関数)で作成した自作関数。 配列変数xy[1]:画像を見つけた座標。xy[0]がX座標、xy[1]がY座標。 |
||
4~25行目 | 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
IF db=1 FUKIDASI(SX1+“,“+SY1,SX1,SY1,0,,,$000000,$00CCEE) FOR i=SX1 TO SX2 step (SX2–SX1)/100 MMV(i,SY1) SLEEP(0.001) NEXT FUKIDASI(SX2+“,“+SY1,SX2,SY1,0,,,$000000,$00CCEE) FOR j=SY1 TO SY2 step (SY2–SY1)/100 MMV(SX2,j) SLEEP(0.001) NEXT FUKIDASI(SX2+“,“+SY2,SX2,SY2,0,,,$000000,$00CCEE) FOR i=SX2 TO SX1 step (SX1–SX2)/100 MMV(i,SY2) SLEEP(0.001) NEXT FUKIDASI(SX1+“,“+SY2,SX1,SY2,0,,,$000000,$00CCEE) FOR j=SY2 TO SY1 step (SY1–SY2)/100 MMV(SX1,j) SLEEP(0.001) NEXT ENDIF |
引数db=1のときは、マウスカーソルを検索範囲の外周に沿って動かします。四隅で座標を吹き出し表示。
4~9行目 : 上の辺を移動 |
||
26~37行目 | 26 27 28 29 30 31 32 33 34 35 36 37 |
SELECT m CASE 1 haba=“IMG_MSK_BGR1“ CASE 2 haba=“IMG_MSK_BGR2“ CASE 3 haba=“IMG_MSK_BGR3“ CASE 4 haba=“IMG_MSK_BGR4“ DEFAULT haba=“IMG_MSK_BGR4“ SELEND |
引数mに従い、CHKIMG()関数へ渡す“色幅”を指定します。 | ||
38~46行目 | 38 39 40 41 42 43 44 45 46 |
IF CHKIMG(pic,,SX1,SY1,SX2,SY2,,haba) xy[0]=G_IMG_X+wh[0]/2 xy[1]=G_IMG_Y+wh[1]/2 FUKIDASI(xy[0]+“,“+xy[1],xy[0],xy[1],0,,,$FFFFFF,$008800) ELSE xy[0]=0 xy[1]=0 FUKIDASI(“画像が見つかりません。“,0,0,0,,,$FFFFFF,$008800) ENDIF |
画像を検索します。 (見つかった場合) 配列変数xy[1]にそれぞれの座標を代入し、見つかった位置に座標を吹き出し表示。 (見つからなかった場合) 座標を(0、0)とし、見つからない由を吹き出し表示します。 |
||
47行目 | 47 | RESULT=SLICE(xy,0,LENGTH(xy)–1) |
関数の戻り値としてX座標とY座標の入った配列変数xy[1]を返します。 |
トラブル時にはこの関数の引数dbを1にしてやることですぐ調べられます。
BMP画像の幅と高さを得る関数 | 見つけた指定画像の中心座標を返す関数 | 高圧縮jpegと劣化なしbmp画像を取得する関数 | あいまいな画像認識の前に“できない理由”を調べる |
本記事の内容は以下でした。
○画像認識ができない理由を掴む
○画像認識ができない理由を掴む
画像をUWSC自身に取得させる
画像の検索範囲をすぐ見れるよう準備
画像の検索範囲をすぐ見れるよう準備
コメント