By using image pre-filtering you can find apriltags at a distance:
# 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?
Um, make sure the res for w and h and a multiple of 8. There’s a bug with set windowing that causes issues if they aren’t I need to fix. Otherwise, yes, it should work.
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.
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.
Was it in grayscale or RGB565? Yes, I agree, there should be no problem with QVGA I’m grayscale. I’ll look into this. I only tried set windowing with VGA when I was testing.
RGB565 images take double the space of a Grayscale image. Athe 200x200 res you’re right at the RAM limit for the M7. (You may wish to actually handle memory exhaustion exceptions at this res).
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.)