質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.13%

テンプレートマッチングで検出した範囲を白抜きしたい

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 98

branch

score 13

Google ColabにてPython 3.8 + OpenCV 4.2.0 で画像処理をしています.
img1から一部を切り出して保存したimg2に対して,テンプレートマッチングによりimg1上のimg2部分を白塗りする関数を作成しようとしているのですが,うまく動きません.
引数image1,image2は画像パスで,返り値は白抜き後画像の配列情報img1を想定しています.
画像はイメージです

試したこと

それぞれ下記スクリプトの if Judg == True:  内の中身です.

  1. img2と同じサイズの白い画像(blank_img)を用意し,テンプレートマッチング結果maxLocから得られたマッチング部分に白い画像を貼り付ける
  2. テンプレートマッチング結果maxLocから,img2と同じ大きさの部分を255(白)にする
  3. maxLocから得られた部分にimg2と同じ大きさのcv2.rectangleで塗りつぶす

特にエラーが出ることもなく,処理に成功しないまま実行完了します...

def erase_img(image1 , image2):  #img1上でimg2と一致するものがあればそこを白塗りする関数
#引数はimg1,img2のパス

    img1 = cv2.imread(image1 , cv2.IMREAD_GRAYSCALE)        #デカい方
    img2 = cv2.imread(image2 , cv2.IMREAD_GRAYSCALE)        #ちっこい方
    blank_img = np.zeros(img2.shape , np.uint8) + 255        #ちっこい方と同じサイズの白画像作成


    #ちっこいの検索開始
    result = cv2.matchTemplate(img2, img1, cv2.TM_CCORR_NORMED)

    #最も類似度が高い位置と低い位置を取得
    minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(result)

    #類似度が閾値を超えているか判定(後述)
    Judg = Judge_Matching(maxVal)

    if Judg == True:  
        img1[ maxLoc[1]: maxLoc[1] + img2.shape[1] , maxLoc[0] : maxLoc[0] + img2.shape[0] ] = blank_img
        img1[ maxLoc[1]: maxLoc[1] + img2.shape[1] , maxLoc[0] : maxLoc[0] + img2.shape[0] ] = 255      #白塗りして保存
        cv2.rectangle(img1, maxLoc , img2.shape , (0, 0, 255), -1)  #黒塗りはどうや?
    return img1 #返り値は処理後の画像

上記のJudge_Matchingは以下の単純な判定関数です.

def Judge_Matching(num):
    if num == 1:
        return True
    else:
        return False

main文

targetimgs = glob.glob("./hoge/*.jpg")
for targetimg in targetimgs:
    print(targetimg)
    baseimg = targetimg.replace("hoge" , "fuga")
    print(baseimg)
    img_out = erase_img( baseimg , targetimg )
    cv2_imshow(img_out)
    cv2.imwrite(baseimg , img_out)


カレントディレクトリ内にhogeとfugaがあり,その中に一定の命名規則に従った画像が保存されています.hoge内の画像image1 は fuga内のimage1からトリミングしたもの であり.上の例だとhoge内にLennaの目が,fuga内にLennaの全体がそれぞれ保存されています.
対応関係を整理しやすいように各画像の命名規則は揃えています.
最終行では関数からの返り値img_outでbaseimgを上書きしています.

かなり初歩的な点かもしれませんが,ここで5日ほど詰まっております.
ご教授のほど,よろしくお願いいたします.

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • yuki23

    2020/06/29 15:00

    どうやって実行しましたか? また、関数定義だけでなく、プログラム全体を載せてください

    キャンセル

  • branch

    2020/06/29 16:45

    早速のご回答ありがとうございます.

    >どうやって実行しましたか?
    に関しては追記しましたが,念のためお知らせします.
    `Google Colab Python 3.8 + OpenCV 4.2.0`です.Ubuntuです.
    Google Colabの仕様で`cv2.imshow`は使えないので,main文の中では`cv2_imshow`としております.
    よろしくお願いいたします.

    キャンセル

回答 2

checkベストアンサー

+1

img2.shape は (W, H) ではなく、(H, W) なので、img2.shape[0] と img2.shape[1] が逆です。

    if Judg == True:
        img1[
            maxLoc[1] : maxLoc[1] + img2.shape[0], maxLoc[0] : maxLoc[0] + img2.shape[1]
        ] = 255  # 白塗りして保存

それはそうとして、if num == 1、つまり、類似度が厳密に1になるというのは、テンプレート画像と全く同じ画素を持つ領域が検索対象の画像にある場合ですので、まずこの条件には引っかからないでしょう。
if maxVal >= 0.8: のように条件をゆるめてみてはどうでしょうか

修正後のコード

import cv2

def erase_img(img_path, templ_path):
    img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
    templ = cv2.imread(templ_path, cv2.IMREAD_GRAYSCALE)

    result = cv2.matchTemplate(img, templ, cv2.TM_CCORR_NORMED)

    # 最も類似度が高い位置と低い位置を取得
    minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(result)


    if maxVal >= 0.8:
        img[
            maxLoc[1] : maxLoc[1] + templ.shape[0],
            maxLoc[0] : maxLoc[0] + templ.shape[1],
        ] = 255

    return img

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/01 07:18 編集

    おはようございます.
    ご回答ありがとうございます.

    無事実装できました!(本当に本当に初歩的なところだったとは....!)

    類似度に関してはトリミング元との比較なので100%では?と思っていたのですが,少し実験的に閾値を探ってみます.
    OpenCV公式によると,どうやら二次元畳み込みを内部的に処理しているようですね.

    http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_imgproc/py_template_matching/py_template_matching.html

    ひとまず,ご忠告通り少し閾値を下げて実行します.

    ありがとうございました.

    キャンセル

  • 2020/07/01 10:54

    類似度算出の式を見ればわかりますが、テンプレート画像が元画像の一部を切り出したものであれば、理論的には1になる箇所はあります。
    https://docs.opencv.org/master/df/dfb/group__imgproc__object.html#gga3a7850640f1fe1f58fe91a2d7583695dab65c042ed62c9e9e095a1e7e41fe2773

    ただ、その場合でも類似度は浮動小数点演算で丸め誤差を含むので、浮動小数点数の比較で == を使ってしまうのはまずいですね

    https://note.nkmk.me/python-math-isclose/

    キャンセル

  • 2020/07/01 12:36

    ご丁寧にありがとうございます.
    95%~90%で固めていこうと思っております.

    また,私事ではございますが,フォローさせていただきました.
    また機会がございましたら,ぜひよろしくお願いします.

    キャンセル

0

この入力は誤りです.

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.13%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる