پردازش تصویر در OpenCV
تطبیق الگو (Template Matching)
اهداف#
در این فصل یاد میگیرید:
- چگونه اشیاء را در یک تصویر با استفاده از تطبیق الگو (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#
در اینجا، به عنوان مثال، چهره مسی را در عکس او جستجو میکنیم. پس یک الگو به صورت زیر ایجاد کردم:
![]()
تمام روشهای مقایسه را امتحان میکنیم تا ببینیم نتایج آنها چگونه است:
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

- cv.TM_CCOEFF_NORMED

- cv.TM_CCORR

- cv.TM_CCORR_NORMED

- cv.TM_SQDIFF

- cv.TM_SQDIFF_NORMED

میتوانید ببینید که نتیجه با استفاده از 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)
نتیجه:
