پردازش تصویر در OpenCV

تطبیق الگو (Template Matching)

۳ دقیقه مطالعهOpenCV 5.xبه‌روزرسانی:

اهداف#

در این فصل یاد می‌گیرید:

  • چگونه اشیاء را در یک تصویر با استفاده از تطبیق الگو (Template Matching) پیدا کنیم
  • با این توابع آشنا می‌شوید: cv.matchTemplate()، cv.minMaxLoc()

تئوری#

تطبیق الگو (Template Matching) روشی برای جستجو و یافتن مکان یک تصویر الگو در یک تصویر بزرگ‌تر است. OpenCV برای این منظور تابع cv.matchTemplate() دارد. این تابع به سادگی تصویر الگو را روی تصویر ورودی می‌لغزاند (مانند پیچیدگی دوبُعدی) و الگو را با پچ تصویر ورودی زیر آن مقایسه می‌کند. چندین روش مقایسه در OpenCV پیاده‌سازی شده‌اند (برای جزئیات بیشتر می‌توانید مستندات را بررسی کنید). این تابع یک تصویر در مقیاس خاکستری برمی‌گرداند که در آن هر پیکسل نشان می‌دهد همسایگی آن پیکسل تا چه اندازه با الگو مطابقت دارد.

اگر تصویر ورودی اندازه (WxH) و تصویر الگو اندازه (wxh) داشته باشد، تصویر خروجی اندازه (W-w+1, H-h+1) خواهد داشت. پس از به دست آوردن نتیجه، می‌توانید از تابع cv.minMaxLoc() برای یافتن مکان بیشینه/کمینه مقدار استفاده کنید. آن را به عنوان گوشه بالا-چپ مستطیل در نظر بگیرید و (w,h) را به عنوان عرض و ارتفاع مستطیل در نظر بگیرید. آن مستطیل، ناحیه الگوی شما است.

تطبیق الگو در OpenCV#

در اینجا، به عنوان مثال، چهره مسی را در عکس او جستجو می‌کنیم. پس یک الگو به صورت زیر ایجاد کردم:

تطبیق الگو (Template Matching) — تصویر ۱

تمام روش‌های مقایسه را امتحان می‌کنیم تا ببینیم نتایج آن‌ها چگونه است:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

img = cv.imread('messi5.jpg', cv.IMREAD_GRAYSCALE)
assert img is not None, "file could not be read, check with os.path.exists()"
img2 = img.copy()
template = cv.imread('template.jpg', cv.IMREAD_GRAYSCALE)
assert template is not None, "file could not be read, check with os.path.exists()"
w, h = template.shape[::-1]

# All the 6 methods for comparison in a list
methods = ['TM_CCOEFF', 'TM_CCOEFF_NORMED', 'TM_CCORR',
            'TM_CCORR_NORMED', 'TM_SQDIFF', 'TM_SQDIFF_NORMED']

for meth in methods:
    img = img2.copy()
    method = getattr(cv, meth)

    # Apply template Matching
    res = cv.matchTemplate(img,template,method)
    min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res)

    # If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum
    if method in [cv.TM_SQDIFF, cv.TM_SQDIFF_NORMED]:
        top_left = min_loc
    else:
        top_left = max_loc
    bottom_right = (top_left[0] + w, top_left[1] + h)

    cv.rectangle(img,top_left, bottom_right, 255, 2)

    plt.subplot(121),plt.imshow(res,cmap = 'gray')
    plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
    plt.subplot(122),plt.imshow(img,cmap = 'gray')
    plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
    plt.suptitle(meth)

    plt.show()

نتایج زیر را ببینید:

  • cv.TM_CCOEFF

تطبیق الگو (Template Matching) — تصویر ۲

  • cv.TM_CCOEFF_NORMED

تطبیق الگو (Template Matching) — تصویر ۳

  • cv.TM_CCORR

تطبیق الگو (Template Matching) — تصویر ۴

  • cv.TM_CCORR_NORMED

تطبیق الگو (Template Matching) — تصویر ۵

  • cv.TM_SQDIFF

تطبیق الگو (Template Matching) — تصویر ۶

  • cv.TM_SQDIFF_NORMED

تطبیق الگو (Template Matching) — تصویر ۷

می‌توانید ببینید که نتیجه با استفاده از cv.TM_CCORR آن‌طور که انتظار داشتیم خوب نیست.

تطبیق الگو با اشیاء متعدد#

در بخش قبلی، تصویر را برای چهره مسی جستجو کردیم که فقط یک بار در تصویر ظاهر می‌شود. فرض کنید به دنبال شیئی هستید که چندین بار ظاهر می‌شود؛ در این صورت cv.minMaxLoc() تمام مکان‌ها را به شما نمی‌دهد. در آن صورت، از آستانه‌گذاری استفاده می‌کنیم. پس در این مثال، از یک اسکرین‌شات از بازی معروف Mario استفاده می‌کنیم و سکه‌های آن را پیدا می‌کنیم.

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

img_rgb = cv.imread('mario.png')
assert img_rgb is not None, "file could not be read, check with os.path.exists()"
img_gray = cv.cvtColor(img_rgb, cv.COLOR_BGR2GRAY)
template = cv.imread('mario_coin.png', cv.IMREAD_GRAYSCALE)
assert template is not None, "file could not be read, check with os.path.exists()"
w, h = template.shape[::-1]

res = cv.matchTemplate(img_gray,template,cv.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where( res >= threshold)
for pt in zip(*loc[::-1]):
    cv.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)

cv.imwrite('res.png',img_rgb)

نتیجه:

تطبیق الگو (Template Matching) — تصویر ۸