# Driver Camera

The simplest useful kind of vision program is one which just pushes an image to the driver station. We do this by using a simple mjpeg stream using mjpeg-streamer . To install, simply run:

pip install mjpeg-streamer

You'll also need OpenCV. Then, the minimally functional program is:

from mjpeg_streamer import MjpegServer, Stream
import cv2

cap = cv2.VideoCapture(0) # replace with whatever camera id you use

stream = Stream("stream_name", size=(640, 480))
server = MjpegServer("127.0.0.1", 1181)
server.add_stream(stream)
server.start()

while True:
    _, frame = cap.read()
    stream.set_frame(frame)

That's a lot, so let's go chunk by chunk:

cap = cv2.VideoCapture(0) # replace with whatever camera id you use

This creates a VideoCapture object around camera 0, but you should swap out 0 for whatever the camera id is. Finding this is notoriously difficult, but if all else fails, try -1, which should use the last available camera.

stream = Stream("stream_name", size=(640, 480))

This creates a mjpeg stream with name stream_name and a specific size. You should change the size parameter to accurately represent the width and height of the images your camera takes in form (width, height).

server = MjpegServer("127.0.0.1", 1181)
server.add_stream(stream)
server.start()

This creates an mjpeg server hosted locally (127.0.0.1 is an ip address that refers to the current computer) on port 1181, accessible from a browser by xx.xx.xx.xx:1181, replacing the xs with the pi's IP address on the network. The stream is then added to the server, and then server is started.

while True:
    _, frame = cap.read()
    stream.set_frame(frame)

Forever, this reads a frame from the camera and then pushes it through the stream.

If you run this program and then navigate to xx.xx.xx.xx:1181, as above, you should be able to see the stream! To stop it, you'll have to press ^C (control-C), potentially twice, to actually stop the program. This will cause it to get a little mad, so to fix that, we can do this instead:

from mjpeg_streamer import MjpegServer, Stream
import cv2

def main():
    cap = cv2.VideoCapture(0) # replace with whatever camera id you use

    stream = Stream("stream_name", size=(640, 480))
    server = MjpegServer("127.0.0.1", 1181)
    server.add_stream(stream)
    server.start()

    while True:
        _, frame = cap.read()
        stream.set_frame(frame)

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        pass

The notable differences are wrapping the code in the function main, and then the if statement at the bottom: __name__ will be set to __main__ if the program is being run from the shell, but not if the file has been imported into another python file; it's just generally a good practice. The try/except KeyboardInterrupt will run main(), which loops until it receives an exception, including a KeyboardInterrupt event (you pressing ^C). By excepting and passing, we can "gracefully" catch the KeyboardInterrupt and end the program from there.

Congratulations, you just wrote your first vision program! Next, we'll look into detecting AprilTags, the new standard for marking FIRST fields.