# Find Small Apriltags
#
# This script shows off how to use blob tracking as a pre-filter to
# finding Apriltags in the image using blob tracking to find the
# area of where the tag is first and then calling find_apriltags
# on that blob.
# Note, this script works well assuming most parts of the image do not
# pass the thresholding test... otherwise, you don't get a distance
# benefit.
import sensor, image, time, math, omv
# Set the thresholds to find a white object (i.e. tag border)
thresholds = (150, 255)
sensor.reset()
sensor.set_pixformat(sensor.GRAYSCALE)
if omv.board_type() == "H7": sensor.set_framesize(sensor.VGA)
elif omv.board_type() == "M7": sensor.set_framesize(sensor.QVGA)
else: raise Exception("You need a more powerful OpenMV Cam to run this script")
sensor.skip_frames(time = 200) # increase this to let the auto methods run for longer
sensor.set_auto_gain(False) # must be turned off for color tracking
sensor.set_auto_whitebal(False) # must be turned off for color tracking
clock = time.clock()
# The apriltag code supports up to 6 tag families which can be processed at the same time.
# Returned tag objects will have their tag family and id within the tag family.
tag_families = 0
tag_families |= image.TAG16H5 # comment out to disable this family
tag_families |= image.TAG25H7 # comment out to disable this family
tag_families |= image.TAG25H9 # comment out to disable this family
tag_families |= image.TAG36H10 # comment out to disable this family
tag_families |= image.TAG36H11 # comment out to disable this family (default family)
tag_families |= image.ARTOOLKIT # comment out to disable this family
while(True):
clock.tick()
img = sensor.snapshot()
# First, we find blobs that may be candidates for tags.
box_list = []
# AprilTags may fail due to not having enough ram given the image sie being passed.
tag_list = []
for blob in img.find_blobs([thresholds], pixels_threshold=100, area_threshold=100, merge=True):
# Next we look for a tag in an ROI that's bigger than the blob.
w = min(max(int(blob.w() * 1.2), 20), 100) # Not too small, not too big.
h = min(max(int(blob.h() * 1.2), 20), 100) # Not too small, not too big.
x = min(max(int(blob.x() - (w * 0.1)), 0), img.width()-1)
y = min(max(int(blob.y() - (h * 0.1)), 0), img.height()-1)
box_list.append((x, y, w, h)) # We'll draw these later.
# Since we constrict the roi size apriltags shouldn't run out of ram.
# But, if it does we handle it...
try:
tag_list.extend(img.find_apriltags(roi=(x,y,w,h), families=tag_families))
except (MemoryError, OSError): # Don't catch all exceptions otherwise you can't stop the script.
pass
for b in box_list:
img.draw_rectangle(b)
# Now print out the found tags
for tag in tag_list:
img.draw_rectangle(tag.rect())
img.draw_cross(tag.cx(), tag.cy())
for c in tag.corners():
img.draw_circle(c[0], c[1], 5)
print("Tag:", tag.cx(), tag.cy(), tag.rotation(), tag.id())

Note that there's a bug in the apriltag code related to the minimum roi. Please don't make the ROI too small. It causes crashes if you do.

In my applications I don't need to see the images and mainly use the IDE just for testing and troubleshooting. My apriltag routines follow your examples pretty closely. I am curious if removing img.draw_ commands will save memory of any significant amount. Is it something to consider?

Hi, I just updated the AprilTag code in the next firmware release. You can do 200x200 on the M7 now and also 100x400 or 400x100 if you know if the tag is vertically or horizontally centered. Can you wait for the new release or do you need it now?

I am doing some bench testing now.
windowing of
200x200
250x160
160x250
400x100
100x400
are all 40000 so match the current multiple of 8 rule.
I think QVGA will work with the best balance for our application but will also try VGA. We need from around 30" to as far as possible. Caregivers are different heights so we also have to balance that with the windowing. So we will see what combination gives the best results.

In my initial testing zoom example on M7 with your firmware showing version 3.0.0 I see the following :
1. Baseline VGA with 160x120 windowing works well
2. Baseline QVGA with 160x120 windowing works well
3. VGA with 200x200 windowing works but not as frequently picking up the tag as 160x120
4. QVGA with 200x200 windowing doesn't work
5. 250x160 windowing doesn't work with either VGA or QVGA

I will try to setup more tests but will take some time. If you improve the firmware in the meantime I will load later versions.

Hi, increasing the resolution results in less detects to do memory limits. There's not much I can do about this. At 200x200 you're at more or less peak memory usage. The firmware fix however greatly improves detection at 160x120 since it frees up a lot of RAM.

I was able to get 200x200 to work staring at a large tag on a screen. However, in a natural environment like the outdoors you have more edges which generates more points in the image which take more RAM to process.

I'm new to OpenMV so I apologize if this is the wrong place for this question, but I see that the program returns the x and y coordinates. Is it possible for Apriltags to return a z coordinate as well? (i.e. the distance between the camera and tag.)