Colour

The blob detector: one colour at a time, area and box width as distance.

4.4VisionRobot club20 min

Do this lesson in the simulator

Tags are for things you put there on purpose. For everything else there is colour. The blob detector finds patches of one colour in the picture and tells you where they are and how big. Two balls, one red and one blue, are on the mat in this lesson.

Pick a colour

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

# camera: look for red blobs
set_cv("blob", "red")
print("red:", blobs())
# camera: look for blue blobs
set_cv("blob", "blue")
print("blue:", blobs())

Run this in the simulator

The blob detector, like the tag detector, runs one thing at a time: one colour. Switch colour with set_cv and read again. Each blob is a list of eight numbers:

[cx, cy, area, x0, y0, x1, y1, aspect]
  • cx, cy: the centre of the blob in pixels, like a tag.
  • area: how many pixels it covers. Bigger means closer, for a ball of a known size.
  • x0, y0, x1, y1: the box around it.
  • aspect: width divided by height. A ball is about 1; a stick lying down is more.

Which side?

cx works the same as for a tag: under 160 is left, over 160 is right.

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

# camera: look for red blobs
set_cv("blob", "red")
red = blobs()[0]
# camera: look for blue blobs
set_cv("blob", "blue")
blue = blobs()[0]
for name, blob in [("red", red), ("blue", blue)]:
    side = "left" if blob[0] < 160 else "right"
    print(name, "is on the", side, "at cx =", blob[0])

Run this in the simulator

How far?

There is no distance in a blob: the detector does not know how big a red thing is in real life. You do. A ball of known size looks smaller the further away it is, so the area tells you the distance:

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

# camera: look for red blobs
set_cv("blob", "red")
# do this 4 times (step counts from 0)
for step in range(4):
    # the blobs of the chosen colour, largest first
    found = blobs()
    if not found:
        print("lost it: out of the picture")
        # leave the loop
        break
    blob = found[0]
    print(f"step {step}: area {blob[2]} px, box {blob[5] - blob[3]} px wide")
    # drive forward at 50 for 4 cm, then stop
    forward(50, distance=4)

Run this in the simulator

The box width grows as the ball gets closer. Width is a better distance guide than area, because area grows with the square of it. Notice the if not found check: the ball is off to one side, and driving straight past it would push it out of the 120 degree view.

Follow the colour

Blob or tag, the servoing loop is the same. Aim at the red ball and drive until it looks big:

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

def bearing_of(cx):
    return (cx - 160) * 120 / 320

# camera: look for red blobs
set_cv("blob", "red")
# again and again, for ever
while True:
    # the blobs of the chosen colour, largest first
    found = blobs()
    if not found:
        # leave the loop
        break
    blob = found[0]
    width = blob[5] - blob[3]
    if width > 40:
        # leave the loop
        break
    # forward, sideways, rotation: -100 to 100 each, until the next command
    drive(50, 0, bearing_of(blob[0]) * 3)
    # pause 0.1 s (the robot keeps doing what it was told)
    wait(0.1)
# all motors off
stop()
print("near the red ball; distance sensor says", distance())

Run this in the simulator

Task: red or blue

Without driving, print left: <colour> and right: <colour> for the two balls.

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

# camera: look for red blobs
set_cv("blob", "red")
print(blobs())

Challenges

  1. Print which ball is nearer, using the box width.
  2. Drive to the blue ball and stop 10 cm from it, checking with distance().
  3. Look for green and yellow too. What does blobs() return when there is nothing of that colour?