UWSC|あいまいな画像認識の前に“できない理由”を調べる

ポク太郎です。

できるだけ画像認識は使わないのが定石。が、やむを得ず必要になることが。

あいまいな画像検索用の関数CHKIMGXが配布されていますが、筆者はまだ試しておりません。

UWSCの開発停止を受けてか、CHKIMGXのダウンロード先が閉鎖。「CHKIMGX」と検索し探して下さい。著作権クリアできるのか不明ですが、配布してる方も居ます。

その前に、標準の画像認識で失敗する理由を確実につかもうと思い、関数を作成しました。


画像認識ができない理由

今、筆者から見えている“画像認識できない”理由は下記です。
※ここではUWSCに比較させるための画像をリファレンス画像と呼んでいます。

1 リファレンス画像と異なるものを検索 
1-1 リファレンス画像をBMPで取得していない

PNGやJPEGなど非可逆圧縮で保存すると元の画像を劣化させてしまうのでBMP(ビットマップ)で保存する必要があります。
1-2 リファレンス画像を保存する際加工されてしまった

AltPrintScreenキーで画像編集ソフトに貼り付けて保存する場合に加工されてしまうものがある。筆者が経験したのはWin10標準アプリの「Paintペイント」。
1-3 グラボによりγカーブが掛けられ色味が異なる

画像を採取したPCと別環境ではグラボが異なるので、別のγカーブが当てられる。初期状態が同じベンダ(nVidia、Radeonなど)同士なら大抵は認識できるが完全には難。
1-4 対象のソフトがアップデートされ異なる表示になってしまった

特にブラウザのような頻繁にアップデートされるソフトではよく遭遇します。
2 検索範囲がずれている
2-1 検索範囲を勘違いしている

処理速度を上げようと画像検索の範囲を絞ろうとした場合などによく陥ります。

通常の画像認識でどこまで確実にできるかを確認するため、デバッグ機能付きの関数を作成します。

※上記の1-3、1-4は回避できませんが、他は回避可能になるので追加機能が必要か確かめることができます。CHKIMGXを使用した場合に1-3、1-4が完全対応できるかどうかは筆者はまだわかっておりません。

スクリーンショット画像をUWSC自身に取得させる

AltPrintScreenキーで画像を取得していると上で挙げた操作ミスなどを招いてしまう&面倒なので、画像を取得する機能を関数として作成しました。

●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秒後に取得”ボタンが押された場合(変数wait1に実行。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を渡す。

ご注意】この関数を使用する際には、グローバル変数として以下を宣言、代入しておく必要があります。
PUBLIC SX1,SY1,SX2,SY2//画像検索範囲用のパラメータ

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 (SX2SX1)/100
            MMV(i,SY1)
            SLEEP(0.001)
      NEXT
            FUKIDASI(SX2+,+SY1,SX2,SY1,0,,,$000000,$00CCEE)
      FOR j=SY1 TO SY2 step (SY2SY1)/100
            MMV(SX2,j)
            SLEEP(0.001)
      NEXT
            FUKIDASI(SX2+,+SY2,SX2,SY2,0,,,$000000,$00CCEE)
      FOR i=SX2 TO SX1 step (SX1SX2)/100
            MMV(i,SY2)
            SLEEP(0.001)
      NEXT
            FUKIDASI(SX1+,+SY2,SX1,SY2,0,,,$000000,$00CCEE)
      FOR j=SY2 TO SY1 step (SY1SY2)/100
            MMV(SX1,j)
            SLEEP(0.001)
      NEXT
   ENDIF
引数db=1のときは、マウスカーソルを検索範囲の外周に沿って動かします。四隅で座標を吹き出し表示。

4~9行目 : 上の辺を移動
10~14行目 : 右の辺を移動
15~19行目 : 下の辺を移動
20~24行目 : 左の辺を移動

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]を返します。



トラブル時にはこの関数の引数db1にしてやることですぐ調べられます。

画像検出の話題
BMP画像の幅と高さを得る関数 見つけた指定画像の中心座標を返す関数 高圧縮jpegと劣化なしbmp画像を取得する関数 あいまいな画像認識の前に“できない理由”を調べる
本記事の内容は以下でした。
○画像認識ができない理由を掴む

画像をUWSC自身に取得させる
画像の検索範囲をすぐ見れるよう準備

コメント

タイトルとURLをコピーしました