When objects are of similar size and shape, like these rainbow donuts, they can be detected using simple template matching in OpenCV:


Template matching is a method for finding the location of a template image in a larger image. This method slides the template image over the input image and compares it to the patch underneath.

This is our template:


The code, based on OpenCV "Mario" example:

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

img_rgb = cv2.imread('table.jpg')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('donut-template.jpg',0)
w, h = template.shape[::-1]

res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)
threshold = 0.7
loc = np.where( res >= threshold)

for pt in zip(*loc[::-1]):
    cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 3)


The result:


Note that increasing the sensitivity (threshold) will result in not finding all the donuts. Setting threshold = 0.95 will only locate one that matches our template exactly:


Setting it too low on more complex images usually results in false positives.

Photographs courtesy of The First Year Blog. Check it out!