OpenCV(Python)で複数の画像データのTemplateMatchingを行うスクリプトを作ってみた

2022.03.08

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、CX事業本部 IoT事業部の若槻です。

前回のエントリでは、OpenCVのTemplate Matchingを使ってみました。

今回はその応用として、OpenCV(Python)で複数の画像データのTemplateMatchingを行うスクリプトを作ってみました。

環境

$  sw_vers  
ProductName:	macOS
ProductVersion:	11.6
BuildVersion:	20G165

$  python
Python 3.9.6 (default, Jun 29 2021, 06:20:32) 
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>> cv2.__version__
'4.5.5'

スクリプト

templateMatch.py

import cv2
import os
import sys
from typing import List, Any
import pprint

ICONS_IMG_FILE_DIR = 'icons/'
TEMPLATE_IMG_FILE_PATH = ICONS_IMG_FILE_DIR + sys.argv[1] + '.jpg'


def get_iconFileNames() -> List[str]:
    return [f.name for f in os.scandir(
        'icons') if f.name.endswith('.jpg')]


def get_iconImgMatList(iconFileNames: List[str]) -> List[Any]:
    def get_matNameDict(iconFileName: str):
        return {
            'mat': cv2.imread(ICONS_IMG_FILE_DIR + iconFileName, cv2.IMREAD_GRAYSCALE),
            'name': iconFileName.replace('.jpg', '')
        }
    return list(map(get_matNameDict, iconFileNames))


def get_templateImgMat() -> Any:
    return cv2.imread(TEMPLATE_IMG_FILE_PATH, cv2.IMREAD_GRAYSCALE)


def get_templateMatchings(icons: List[Any], template: Any) -> List[object]:
    def get_nameValDict(icon: Any):
        return {
            'name': icon['name'],
            'val': cv2.matchTemplate(icon['mat'], template, cv2.TM_CCORR_NORMED)[0][0]
        }
    return list(map(get_nameValDict, icons))


def main() -> None:
    iconFileNames = get_iconFileNames()
    iconImgMatList = get_iconImgMatList(iconFileNames)
    templateImgMat = get_templateImgMat()
    templateMatchedList = get_templateMatchings(iconImgMatList, templateImgMat)

    pprint.pprint(sorted(templateMatchedList,
                  key=lambda x: x['val'], reverse=True))


main()

動作

検索対象としてAWSサービスのアイコン画像を用意。

引数にテンプレートとしたいサービスを指定してスクリプトを実行すると、各種アイコン画像に対してTemplateMatchingが行われ、適合度順で結果を取得できます。

Amazon_EFSのアイコンは、Amazon_EC2が最も適合度が高く、AWS_CodeBuildが最も低いとのこと。

$  python templateMatch.py Amazon_EFS
[{'name': 'Amazon_EFS', 'val': 1.0},
 {'name': 'Amazon_EC2', 'val': 0.9395257},
 {'name': 'AWS_Lambda', 'val': 0.93662506},
 {'name': 'Amazon_CloudWatch', 'val': 0.89988333},
 {'name': 'Amazon_SageMaker', 'val': 0.89924395},
 {'name': 'Amazon_AWS_Organizations', 'val': 0.89269716},
 {'name': 'Amazon_KinesisVideoStream', 'val': 0.8878451},
 {'name': 'Amazon_CloudFront', 'val': 0.88632554},
 {'name': 'Amazon_KinesisDataAnalytics', 'val': 0.88607734},
 {'name': 'Amazon_QuickSight', 'val': 0.8835226},
 {'name': 'AWS_IAM', 'val': 0.8807701},
 {'name': 'AWS_CodeBuild', 'val': 0.8734735}]

Amazon_KinesisDataAnalyticsのアイコンは、Amazon_KinesisVideoStreamと最も適合度が高いとのことで、両者はアイコンが似ているのでこれは納得です。TemplateMatchingによる検出が上手く出来ているようですね。

$  python templateMatch.py Amazon_KinesisDataAnalytics
[{'name': 'Amazon_KinesisDataAnalytics', 'val': 0.99999994},
 {'name': 'Amazon_KinesisVideoStream', 'val': 0.9644058},
 {'name': 'AWS_Lambda', 'val': 0.9121719},
 {'name': 'Amazon_EC2', 'val': 0.90480083},
 {'name': 'Amazon_CloudWatch', 'val': 0.8934901},
 {'name': 'Amazon_EFS', 'val': 0.88607734},
 {'name': 'Amazon_SageMaker', 'val': 0.8837707},
 {'name': 'Amazon_AWS_Organizations', 'val': 0.8824213},
 {'name': 'Amazon_CloudFront', 'val': 0.8748613},
 {'name': 'Amazon_QuickSight', 'val': 0.8735345},
 {'name': 'AWS_IAM', 'val': 0.87245643},
 {'name': 'AWS_CodeBuild', 'val': 0.84382296}]

おわりに

OpenCV(Python)で複数の画像データのTemplateMatchingを行うスクリプトを作ってみました。

TemplateMatchingの部分は前回から特に変わったことはしていないのですが、Pythonのスクリプトを組むのが久しぶり過ぎて思い出すのに苦労しました。

以上