Skip to content

Commit 908ad71

Browse files
committed
Add SFE logo detection example
1 parent 604874b commit 908ad71

File tree

1 file changed

+126
-0
lines changed

1 file changed

+126
-0
lines changed

examples/ex05_detect_sfe_logo.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# Import OpenCV
2+
import cv2
3+
from cv2_hardware_init import *
4+
from ulab import numpy as np
5+
import time
6+
7+
# Here we define a reference contour for the SparkFun flame logo. This was
8+
# created manually by picking points on the boundary of a small image of the
9+
# logo in an image editor. This gets drawn in the top left corner of the
10+
# display for reference
11+
logo_contour = np.array(
12+
[[[0,48]],
13+
[[0,22]],
14+
[[4,16]],
15+
[[9,16]],
16+
[[7,19]],
17+
[[10,22]],
18+
[[13,22]],
19+
[[16,19]],
20+
[[16,17]],
21+
[[10,10]],
22+
[[10,5]],
23+
[[15,1]],
24+
[[20,0]],
25+
[[24,2]],
26+
[[19,5]],
27+
[[19,8]],
28+
[[23,12]],
29+
[[26,11]],
30+
[[26,8]],
31+
[[32,14]],
32+
[[32,25]],
33+
[[28,32]],
34+
[[20,36]],
35+
[[12,36]]], dtype=np.float)
36+
37+
# Initialize a loop timer to calculate processing speed in FPS
38+
loop_time = time.ticks_us()
39+
40+
# Open the camera
41+
camera.open()
42+
43+
# Prompt the user to press a key to continue
44+
print("Press any key to continue")
45+
46+
# Loop to continuously read frames from the camera and display them
47+
while True:
48+
# Read a frame from the camera
49+
success, frame = camera.read()
50+
51+
# Here we binarize the image. There are many ways to do this, but here we
52+
# simply convert the image to grayscale and then apply Otsu's thresholding
53+
# method to create a binary image. This means it will only detect a dark
54+
# logo on a light background (or vice versa), but you can modify this to
55+
# find specific colors or use other methods if desired
56+
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
57+
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
58+
59+
# Find contours in the binary image, which represent the boundaries of
60+
# shapes. Contours are a powerful tool in OpenCV for shape analysis and
61+
# object detection
62+
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
63+
64+
# It's possible that no contours were found, so first check if any were
65+
# found before proceeding
66+
if contours:
67+
# We'll compare the contours found in the image to the reference logo
68+
# contour defined earlier. We will use the `cv2.matchShapes()` function
69+
# to compare the shapes to pick the best match, so we need to initialize
70+
# variables to keep track of the best match found so far
71+
best_contour = None
72+
best_similarity = float('inf') # Start with a very high similarity score
73+
74+
# Loop through each contour found in the image to find the best match
75+
for i in range(len(contours)):
76+
# If the image is noisy, the binarized image may contain many tiny
77+
# contours that are obviously not the logo. `cv2.matchShapes()` can
78+
# take some time, so we can be more efficient by skipping obviously
79+
# wrong contours. In this example, the logo we're looking for is
80+
# fairly complex, so we can skip contours that have too few points
81+
# since they will definitely be too simple to match the logo
82+
if len(contours[i]) < 20:
83+
continue
84+
85+
# Now we call `cv2.matchShapes()` which returns a "similarity" score
86+
# between the two shapes. The lower the score, the more similar the
87+
# shapes are
88+
similarity = cv2.matchShapes(logo_contour, contours[i], cv2.CONTOURS_MATCH_I2, 0)
89+
90+
# Check if this contour is a better match than the best so far
91+
if similarity < best_similarity:
92+
# This contour is a better match, so update the best match
93+
best_similarity = similarity
94+
best_contour = contours[i]
95+
96+
# We're done checking all contours. It's possible that the best contour
97+
# found is not a good match, so we can check if the score is below a
98+
# threshold to determine whether it's close enough. Testing has shown
99+
# that good matches are usually around 0.5, so we'll use a slightly
100+
# higher threshold of 1.0
101+
if best_similarity < 1.0:
102+
# Now we'll draw the best contour found on the original image
103+
frame = cv2.drawContours(frame, [best_contour], -1, (0, 0, 255), 2)
104+
105+
# All processing is done! Calculate the frame rate and display it
106+
current_time = time.ticks_us()
107+
fps = 1000000 / (current_time - loop_time)
108+
loop_time = current_time
109+
frame = cv2.putText(frame, f"FPS: {fps:.2f}", (40, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
110+
111+
# Draw the reference logo contour in the top left corner of the frame
112+
frame[0:50, 0:40] = (0,0,0)
113+
frame = cv2.drawContours(frame, [logo_contour], -1, (255, 255, 255), 1, offset=(2, 2))
114+
115+
# Display the frame
116+
cv2.imshow(display, frame)
117+
118+
# Check for key presses
119+
key = cv2.waitKey(1)
120+
121+
# If any key is pressed, exit the loop
122+
if key != -1:
123+
break
124+
125+
# Release the camera
126+
camera.release()

0 commit comments

Comments
 (0)