2007年6月21日木曜日

画像の完全一致検索


本家BBSにてHSPCVプラグインのcvmatchが話題になっていたので、標準命令(VRAM操作)で強引に検索するモジュールを作成。思ってたよりは高速でした。

なかなか良い変数名が思いつかず苦戦。

// VRAMを使って画像を探すモジュール(^-^;
// 速度向上のために条件分岐を減らすため、フルカラーモード専用。
// 参考:http://hspwiki.tm.land.to/?%BE%AE%A5%EF%A5%B6%2FVRAM%A4%F2%C4%BE%C0%DC%C1%E0%BA%EE%A4%B7%A4%C6%A4%DF%A4%EB
#module PicMatchModule
#const global SUCCESS 0
#const global FAILURE 1

#deffunc picMatch var xMatched, var yMatched, int idTarget, int idSource, local iResult, local targetVRAM, local sourceVRAM
    xMatched = -1 : yMatched = -1 : iResult = 0

    // ウィンドウサイズの取得
    gsel idSource : sourceWinx = ginfo_winx : sourceWiny = ginfo_winy
    gsel idTarget : targetWinx = ginfo_winx : targetWiny = ginfo_winy
    if (targetWinx < sourceWinx) | (targetWiny < sourceWiny) {
        // 画像サイズが大きすぎる
        return FAILURE
    }

    gsel idSource : mref sourceVRAM, 66
    gsel idTarget : mref targetVRAM, 66
    sourceWidth = (sourceWinx * 3 + 3) & 0xfffffffc         // VRAM1行あたりのバイト数
    targetWidth = (targetWinx * 3 + 3) & 0xfffffffc

    repeat targetWiny - sourceWiny + 1
        y = cnt                         // 検索開始位置左上Y座標
        repeat targetWinx - sourceWinx + 1
            x = cnt                     // 検索開始位置左上X座標
            iResult = SUCCESS
            repeat sourceWiny
                ty = cnt                // 調査対象座標をyから見た時の相対的なY座標
                repeat sourceWinx
                    tx = cnt            // 調査対象座標をxから見た時の相対的なX座標

                    index = (targetWiny - y - ty - 1) * targetWidth + (x + tx) * 3
                    colorTarget = (peek(targetVRAM, index + 2) << 16) | (peek(targetVRAM, index + 1) << 8) | peek(targetVRAM, index)

                    index = (sourceWiny - ty - 1) * sourceWidth + tx * 3
                    colorSource = (peek(sourceVRAM, index + 2) << 16) | (peek(sourceVRAM, index + 1) << 8) | peek(sourceVRAM, index)

                    if(colorTarget != colorSource) {
                        iResult = FAILURE
                        break
                    }
                loop
                if iResult == FAILURE : break
            loop
            if (iResult == SUCCESS) {   // マッチした
                xMatched = x : yMatched = y
                break
            }
            await 1
        loop
        if (iResult == SUCCESS) : break
    loop
    return iResult
#global

// 以下、サンプルスクリプト
    randomize
    screen 024040                   // 横幅は4の倍数でなくともよい
    mes "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    pos 020
    serch = "A"
    input serch, 160201
    pos 16020 : objsize 8020
    button gosub "検索"*serchStart
    title "検索する文字を入力してください"
    stop

*serchStart
    if serch == "" : return
    gsel 0
    color 255255255 : boxf
    color : pos 00
    mes "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    pos ginfo_winx : mes serch
    mesx = ginfo_mesx : mesy = ginfo_mesy
    buffer 1, mesx, mesy : cls 0
    pos 00 : mes serch
    gsel 0
    title "検索中..."
    picMatch x, y, 01
    if (stat == SUCCESS) {
        gsel 0 : color 255
        line x + mesx, y, x, y
        line x + mesx, y + mesy
        line x, y + mesy
        line x, y
        dialog "Match!:" + x + "," + y
    } else {
        gsel 0
        dialog "Not Match."
    }
    title "検索する文字を入力してください"
    return

2 件のコメント:

匿名 さんのコメント...

>なかなか良い変数名が思いつかず苦戦

僕は重要そうなのに、たいした使わず、なかなか思いつかない変数名/関数名 は
日本語で書いています。見栄えは良くないかもしれないけれど
わけのわからない/短い のよりは良いと思っています

日本語の命名は「なでしこ」の本を読んでからでしょうか
ちなみに「なでしこ」でコーディングしたことはないです

それでは、失礼しました、そして、ここでは初めましてですね
これからも良いアイデアのスクリプトを書いていっていただければ
僕は楽しい気分になるでしょう
--りすと

eller さんのコメント...

コメントありがとうございます。
相互リンクの件、お待ちしていますよー。

変数名に半角英字を使うのがポリシー(?)なので、ここは譲れない感じです。
日本語はスクリプトという"地"の中で"図"として浮かび上がってしまうので読みにくいですし、なにより将来仕事でコーディングする時のことを考えて今から半角英字のネーミングに慣れておきたいと考えているからです。

まぁ練習なんてしなくても社内規定に沿えばOKなのでしょうけれども(^.^;

またアイデアが出て、載せて有用であると判断したら乗せたいと思います。
気長にお付き合いくださいませ。