{
  "source_file": "0930",
  "source_platform": "技术平台",
  "author": "OpenCV",
  "title_listed": "Template Matching",
  "keywords": "模板匹配,相似度",
  "domain": "图像处理",
  "content_type": "官方教程",
  "is_paid_flag": "否",
  "url": "https://docs.opencv.org/4.x/d4/dc6/tutorial_py_template_matching.html",
  "publish_date": "持续更新",
  "corpus_stage": "图像处理",
  "notes": "模板匹配",
  "id": "04d2263caef8",
  "collected_at": "2026-10-02T18:37:50",
  "title": "OpenCV: Template Matching",
  "body_markdown": "In this chapter, you will learn\nTemplate Matching is a method for searching and finding the location of a template image in a larger image. OpenCV comes with a function [cv.matchTemplate()](../../df/dfb/group__imgproc__object.html#ga586ebfb0a7fb604b35a23d85391329be) for this purpose. It simply slides the template image over the input image (as in 2D convolution) and compares the template and patch of input image under the template image. Several comparison methods are implemented in OpenCV. (You can check docs for more details). It returns a grayscale image, where each pixel denotes how much does the neighbourhood of that pixel match with template.\nIf input image is of size (WxH) and template image is of size (wxh), output image will have a size of (W-w+1, H-h+1). Once you got the result, you can use [cv.minMaxLoc()](../../d2/de8/group__core__array.html#gab473bf2eb6d14ff97e89b355dac20707) function to find where is the maximum/minimum value. Take it as the top-left corner of rectangle and take (w,h) as width and height of the rectangle. That rectangle is your region of template.\n- Note\n- If you are using [cv.TM_SQDIFF](../../df/dfb/group__imgproc__object.html#gga3a7850640f1fe1f58fe91a2d7583695dab65c042ed62c9e9e095a1e7e41fe2773) as comparison method, minimum value gives the best match.\nHere, as an example, we will search for Messi's face in his photo. So I created a template as below:\nimage\n    We will try all the comparison methods so that we can see how their results look like: \nimport cv2 as cv\nimport numpy as np\nfrom matplotlib import pyplot as plt\n \nimg = [cv.imread](../../d4/da8/group__imgcodecs.html#gaffb68fce322c6e52841d7d9357b9ad2d)('messi5.jpg', cv.IMREAD_GRAYSCALE)\nassert img is not None, \"file could not be read, check with os.path.exists()\"\nimg2 = img.copy()\ntemplate = [cv.imread](../../d4/da8/group__imgcodecs.html#gaffb68fce322c6e52841d7d9357b9ad2d)('template.jpg', cv.IMREAD_GRAYSCALE)\nassert template is not None, \"file could not be read, check with os.path.exists()\"\nw, h = template.shape[::-1]\n \nmethods = ['TM_CCOEFF', 'TM_CCOEFF_NORMED', 'TM_CCORR',\n            'TM_CCORR_NORMED', 'TM_SQDIFF', 'TM_SQDIFF_NORMED']\n \nfor meth in methods:\n    img = img2.copy()\n    method = getattr(cv, meth)\n \n    \n    res = [cv.matchTemplate](../../df/dfb/group__imgproc__object.html#ga586ebfb0a7fb604b35a23d85391329be)(img,template,method)\n    min_val, max_val, min_loc, max_loc = [cv.minMaxLoc](../../d2/de8/group__core__array.html#gab473bf2eb6d14ff97e89b355dac20707)(res)\n \n    \n    if method in [cv.TM_SQDIFF, cv.TM_SQDIFF_NORMED]:\n        top_left = min_loc\n    else:\n        top_left = max_loc\n    bottom_right = (top_left[0] + w, top_left[1] + h)\n \n    [cv.rectangle](../../d6/d6e/group__imgproc__draw.html#ga07d2f74cadcf8e305e810ce8eed13bc9)(img,top_left, bottom_right, 255, 2)\n \n    plt.subplot(121),plt.imshow(res,cmap = 'gray')\n    plt.title('Matching Result'), plt.xticks([]), plt.yticks([])\n    plt.subplot(122),plt.imshow(img,cmap = 'gray')\n    plt.title('Detected Point'), plt.xticks([]), plt.yticks([])\n    plt.suptitle(meth)\n \n    plt.show()\nvoid minMaxLoc(InputArray src, double *minVal, double *maxVal=0, Point *minLoc=0, Point *maxLoc=0, InputArray mask=noArray())\nFinds the global minimum and maximum in an array.\nMat imread(const String &filename, int flags=IMREAD_COLOR_BGR)\nLoads an image from a file.\nvoid rectangle(InputOutputArray img, Point pt1, Point pt2, const Scalar &color, int thickness=1, int lineType=LINE_8, int shift=0)\nDraws a simple, thick, or filled up-right rectangle.\nvoid matchTemplate(InputArray image, InputArray templ, OutputArray result, int method, InputArray mask=noArray())\nCompares a template against overlapped image regions.\n See the results below:\nimage\n    \nimage\n    \nimage\n    \nimage\n    \nimage\n    \nimage\n    You can see that the result using [cv.TM_CCORR](../../df/dfb/group__imgproc__object.html#gga3a7850640f1fe1f58fe91a2d7583695da5be00b45a4d99b5e42625b4400bfde65) is not good as we expected.\nIn the previous section, we searched image for Messi's face, which occurs only once in the image. Suppose you are searching for an object which has multiple occurrences, [cv.minMaxLoc()](../../d2/de8/group__core__array.html#gab473bf2eb6d14ff97e89b355dac20707) won't give you all the locations. In that case, we will use thresholding. So in this example, we will use a screenshot of the famous game Mario and we will find the coins in it. \nimport cv2 as cv\nimport numpy as np\nfrom matplotlib import pyplot as plt\n \nimg_rgb = [cv.imread](../../d4/da8/group__imgcodecs.html#gaffb68fce322c6e52841d7d9357b9ad2d)('mario.png')\nassert img_rgb is not None, \"file could not be read, check with os.path.exists()\"\nimg_gray = [cv.cvtColor](../../d8/d01/group__imgproc__color__conversions.html#gaf86c09fe702ed037c03c2bc603ceab14)(img_rgb, cv.COLOR_BGR2GRAY)\ntemplate = [cv.imread](../../d4/da8/group__imgcodecs.html#gaffb68fce322c6e52841d7d9357b9ad2d)('mario_coin.png', cv.IMREAD_GRAYSCALE)\nassert template is not None, \"file could not be read, check with os.path.exists()\"\nw, h = template.shape[::-1]\n \nres = [cv.matchTemplate](../../df/dfb/group__imgproc__object.html#ga586ebfb0a7fb604b35a23d85391329be)(img_gray,template,cv.TM_CCOEFF_NORMED)\nthreshold = 0.8\nloc = np.where( res >= threshold)\nfor pt in zip(*loc[::-1]):\n    [cv.rectangle](../../d6/d6e/group__imgproc__draw.html#ga07d2f74cadcf8e305e810ce8eed13bc9)(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)\n \n[cv.imwrite](../../d4/da8/group__imgcodecs.html#gabbc7ef1aa2edfaa87772f1202d67e0ce)('res.png',img_rgb)\nbool imwrite(const String &filename, InputArray img, const std::vector< int > ¶ms=std::vector< int >())\nSaves an image to a specified file.\nvoid cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0, AlgorithmHint hint=cv::ALGO_HINT_DEFAULT)\nConverts an image from one color space to another.\n Result:\nimage",
  "metadata": {
    "title": "OpenCV: Template Matching",
    "engine": "curl_cffi"
  },
  "paywall": {
    "listed_paid": false,
    "detected": false,
    "marker": "",
    "public_only": false,
    "policy": "付费/会员内容只保留页面公开可见部分，不绕过付费墙"
  },
  "crawl": {
    "success": true,
    "status_code": 200,
    "error": "",
    "retried": true,
    "engine": "curl_cffi+trafilatura"
  },
  "code_blocks": [],
  "images": [],
  "audio": [],
  "videos": [],
  "links": [
    {
      "type": "external",
      "href": "https://www.cloudflare.com"
    },
    {
      "type": "external",
      "href": "https://www.cloudflare.com/privacypolicy/"
    }
  ],
  "retry_at": "2026-10-03T08:12:20",
  "final_url": "https://docs.opencv.org/4.13.0/d4/dc6/tutorial_py_template_matching.html",
  "repair_version": 2,
  "repaired_at": "2026-10-20T17:30:11Z",
  "source_url": "https://docs.opencv.org/4.x/d4/dc6/tutorial_py_template_matching.html",
  "delivery_status": "unverified",
  "discovery_status": "http_403",
  "missing_reason": "http_403",
  "repair_error": "",
  "actual_video_files": [],
  "source_body_markdown": "In this chapter, you will learn\nTemplate Matching is a method for searching and finding the location of a template image in a larger image. OpenCV comes with a function [cv.matchTemplate()](../../df/dfb/group__imgproc__object.html#ga586ebfb0a7fb604b35a23d85391329be) for this purpose. It simply slides the template image over the input image (as in 2D convolution) and compares the template and patch of input image under the template image. Several comparison methods are implemented in OpenCV. (You can check docs for more details). It returns a grayscale image, where each pixel denotes how much does the neighbourhood of that pixel match with template.\nIf input image is of size (WxH) and template image is of size (wxh), output image will have a size of (W-w+1, H-h+1). Once you got the result, you can use [cv.minMaxLoc()](../../d2/de8/group__core__array.html#gab473bf2eb6d14ff97e89b355dac20707) function to find where is the maximum/minimum value. Take it as the top-left corner of rectangle and take (w,h) as width and height of the rectangle. That rectangle is your region of template.\n- Note\n- If you are using [cv.TM_SQDIFF](../../df/dfb/group__imgproc__object.html#gga3a7850640f1fe1f58fe91a2d7583695dab65c042ed62c9e9e095a1e7e41fe2773) as comparison method, minimum value gives the best match.\nHere, as an example, we will search for Messi's face in his photo. So I created a template as below:\nimage\n    We will try all the comparison methods so that we can see how their results look like: \nimport cv2 as cv\nimport numpy as np\nfrom matplotlib import pyplot as plt\n \nimg = [cv.imread](../../d4/da8/group__imgcodecs.html#gaffb68fce322c6e52841d7d9357b9ad2d)('messi5.jpg', cv.IMREAD_GRAYSCALE)\nassert img is not None, \"file could not be read, check with os.path.exists()\"\nimg2 = img.copy()\ntemplate = [cv.imread](../../d4/da8/group__imgcodecs.html#gaffb68fce322c6e52841d7d9357b9ad2d)('template.jpg', cv.IMREAD_GRAYSCALE)\nassert template is not None, \"file could not be read, check with os.path.exists()\"\nw, h = template.shape[::-1]\n \nmethods = ['TM_CCOEFF', 'TM_CCOEFF_NORMED', 'TM_CCORR',\n            'TM_CCORR_NORMED', 'TM_SQDIFF', 'TM_SQDIFF_NORMED']\n \nfor meth in methods:\n    img = img2.copy()\n    method = getattr(cv, meth)\n \n    \n    res = [cv.matchTemplate](../../df/dfb/group__imgproc__object.html#ga586ebfb0a7fb604b35a23d85391329be)(img,template,method)\n    min_val, max_val, min_loc, max_loc = [cv.minMaxLoc](../../d2/de8/group__core__array.html#gab473bf2eb6d14ff97e89b355dac20707)(res)\n \n    \n    if method in [cv.TM_SQDIFF, cv.TM_SQDIFF_NORMED]:\n        top_left = min_loc\n    else:\n        top_left = max_loc\n    bottom_right = (top_left[0] + w, top_left[1] + h)\n \n    [cv.rectangle](../../d6/d6e/group__imgproc__draw.html#ga07d2f74cadcf8e305e810ce8eed13bc9)(img,top_left, bottom_right, 255, 2)\n \n    plt.subplot(121),plt.imshow(res,cmap = 'gray')\n    plt.title('Matching Result'), plt.xticks([]), plt.yticks([])\n    plt.subplot(122),plt.imshow(img,cmap = 'gray')\n    plt.title('Detected Point'), plt.xticks([]), plt.yticks([])\n    plt.suptitle(meth)\n \n    plt.show()\nvoid minMaxLoc(InputArray src, double *minVal, double *maxVal=0, Point *minLoc=0, Point *maxLoc=0, InputArray mask=noArray())\nFinds the global minimum and maximum in an array.\nMat imread(const String &filename, int flags=IMREAD_COLOR_BGR)\nLoads an image from a file.\nvoid rectangle(InputOutputArray img, Point pt1, Point pt2, const Scalar &color, int thickness=1, int lineType=LINE_8, int shift=0)\nDraws a simple, thick, or filled up-right rectangle.\nvoid matchTemplate(InputArray image, InputArray templ, OutputArray result, int method, InputArray mask=noArray())\nCompares a template against overlapped image regions.\n See the results below:\nimage\n    \nimage\n    \nimage\n    \nimage\n    \nimage\n    \nimage\n    You can see that the result using [cv.TM_CCORR](../../df/dfb/group__imgproc__object.html#gga3a7850640f1fe1f58fe91a2d7583695da5be00b45a4d99b5e42625b4400bfde65) is not good as we expected.\nIn the previous section, we searched image for Messi's face, which occurs only once in the image. Suppose you are searching for an object which has multiple occurrences, [cv.minMaxLoc()](../../d2/de8/group__core__array.html#gab473bf2eb6d14ff97e89b355dac20707) won't give you all the locations. In that case, we will use thresholding. So in this example, we will use a screenshot of the famous game Mario and we will find the coins in it. \nimport cv2 as cv\nimport numpy as np\nfrom matplotlib import pyplot as plt\n \nimg_rgb = [cv.imread](../../d4/da8/group__imgcodecs.html#gaffb68fce322c6e52841d7d9357b9ad2d)('mario.png')\nassert img_rgb is not None, \"file could not be read, check with os.path.exists()\"\nimg_gray = [cv.cvtColor](../../d8/d01/group__imgproc__color__conversions.html#gaf86c09fe702ed037c03c2bc603ceab14)(img_rgb, cv.COLOR_BGR2GRAY)\ntemplate = [cv.imread](../../d4/da8/group__imgcodecs.html#gaffb68fce322c6e52841d7d9357b9ad2d)('mario_coin.png', cv.IMREAD_GRAYSCALE)\nassert template is not None, \"file could not be read, check with os.path.exists()\"\nw, h = template.shape[::-1]\n \nres = [cv.matchTemplate](../../df/dfb/group__imgproc__object.html#ga586ebfb0a7fb604b35a23d85391329be)(img_gray,template,cv.TM_CCOEFF_NORMED)\nthreshold = 0.8\nloc = np.where( res >= threshold)\nfor pt in zip(*loc[::-1]):\n    [cv.rectangle](../../d6/d6e/group__imgproc__draw.html#ga07d2f74cadcf8e305e810ce8eed13bc9)(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)\n \n[cv.imwrite](../../d4/da8/group__imgcodecs.html#gabbc7ef1aa2edfaa87772f1202d67e0ce)('res.png',img_rgb)\nbool imwrite(const String &filename, InputArray img, const std::vector< int > ¶ms=std::vector< int >())\nSaves an image to a specified file.\nvoid cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0, AlgorithmHint hint=cv::ALGO_HINT_DEFAULT)\nConverts an image from one color space to another.\n Result:\nimage",
  "body_base_path": "attachments/04d2263caef8/pages/",
  "body_markdown_path": "attachments/04d2263caef8/pages/archived-body.md",
  "local_html": "attachments/04d2263caef8/pages/archived-body.html",
  "body_source": "prior_capture"
}