Running a Python + OpenCV script on reboot

Datetime:2016-08-22 23:38:24          Topic: Python  OpenCV           Share

Here’s a common question I get asked on the PyImageSearch blog:

How do I make a Python + OpenCV script start as soon as my system boots up?

There are many ways to accomplish. By my favorite is to use crontab and the @reboot option .

The main reason I like this method so much is because crontab exists on nearly every Unix machine (plus, crontab is a really neat utility that I think everyone should have at least some experience with).

It doesn’t matter if you’re on Raspbian, Linux, or OSX — crontab is likely to be installed on your system.

In the remainder of this blog post, I’ll demonstrate how to utilize crontab to start a Python + OpenCV script when your system boots up.

Looking for the source code to this post?

Jump right to the downloads section.

Running a Python + OpenCV script on reboot

As I mentioned in the introduction to this blog post, we’ll be using crontab to launch a script on system reboot.

I’ll be using my Raspberry Pi to accomplish, but the same general instructions apply for other Linux distributions and OSX as well — all you need to do is change the paths to your scripts.

An example application

In last week’s post, I demonstrated how to create an “alarm” program that detects this green ball in a video stream:

Figure 1:The green ball we will be detecting in our video stream.

If this green ball is detected, an alarm is raised by activating a buzzer and lighting up an LED on the TrafficHAT module (which is connected to a Raspberry Pi):

Figure 2:The TrafficHAT module for the Raspberry Pi, which includes 3 LED lights, a buzzer, and push button, all of which are programmable via GPIO.

An example of the “activated alarm” can be seen below:

Figure 3:Notice how when the green ball is detected in the video stream, the LED on the TrafficHAT lights up.

Here we can see the green ball is in view of the camera. Our program is able to detect the presence of the ball , light up an LED on the board , and if there was sound, you could hear the buzzer going off as well .

Today, we are going to take this example alarm program and modify it so that it can be started automatically when the Raspberry Pi boots up — we will  not have to manually execute  any command to start our alarm program.

Creating the launcher

Before we can execute our Python script on reboot, we first need to create a shell script that performs two important tasks:

  1. (Optional) Accesses our Python virtual environment. I’ve marked this step as  optional only because in some cases, you may not be using a Python virtual environment. But if you’ve followed  any of the OpenCV install tutorials on this blog , then this step  is not optional since your OpenCV bindings are stored in a virtual environment.
  2. Executes our Python script. This is where all the action happens. We need to (1) change directory to where our Python script lives and (2) execute it.

Accomplishing both these tasks is actually quite simple.

Below I have included the contents of my on_reboot . sh shell script which I have placed in / home / pi / pi - reboot :

#!/bin/bash
 
source /home/pi/.profile
workoncv
cd /home/pi/pi-reboot
pythonpi_reboot_alarm.py

When we reboot our Pi, the on_reboot . sh script will be running as the root user (provided that you edit the root crontab, of course; which we’ll cover in the next section).

However, we first need to access the cv virtual environment (or whatever Python virtual environment you are using), so we’ll call source / home / pi / . profile to setup the virtual environment scripts, followed by workon cv to drop us into the cv environment.

Note:To learn about Python virtual environments, please refer to this post .

After we have setup our environment, we change directory to / home / pi / pi - reboot , which is where I have stored the pi_reboot_alarm . py script.

Finally, we are ready to execute pi_reboot_alarm . py — executing this script will be done within the cv virtual environment (thanks to the source and workon commands).

Note: Again, make sure you have read both the accessing RPi.GPIO and GPIO Zero with OpenCV post and the OpenCV, RPi.GPIO, and GPIO Zero on the Raspberry Pi post before continuing with this tutorial. Both of these posts contain important information on configuring your development environment and installing required Python packages.

After adding these lines to to your on_reboot . sh , save the file and then. Then, to make it executable, you’ll need to chmod it:

$ chmod +x on_reboot.sh

After changing the permissions of the file to executable, you’re ready to move on to the next step!

Updating crontab

Now that we have defined the on_reboot . sh shell script, let’s update the crontab to call it on system reboot.

Simply start by executing the following command to edit the root user’s crontab:

$ sudocrontab -e

This command should bring up the crontab file, which should look something like this:

Figure 4:An example of crontab file.

You should then enter the following lines at the bottom of the file :

@reboot /home/pi/pi-reboot/on_reboot.sh

This command instructs the system to execute the on_reboot . sh script whenever our system is rebooted.

Note:You can obviously replace the path to on_reboot . sh with your own shell script.

Once you have finished editing the crontab, save the file and exit the editor — the changes to crontab will be automatically applied. Then at next reboot, the on_reboot . sh script will be automatically executed.

Creating our Python script

The contents of pi_reboot_alarm . py are near identical to last week’s blog post on OpenCV, RPi.GPIO, and GPIO Zero on the Raspberry Pi , but I’ve included the contents of the script as a matter of completeness:

# import the necessary packages
from imutils.videoimport VideoStream
from gpiozeroimport TrafficHat
import argparse
import datetime
import logging
import imutils
import time
import cv2
 
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-p", "--picamera", type=int, default=-1,
 help="whether or not the Raspberry Pi camera should be used")
ap.add_argument("-l", "--log", type=str, default="log.txt",
 help="path to output log file")
args = vars(ap.parse_args())

Lines 2-9handle importing our required Python packages. We’ll be using VideoStream to seamlessly access either the Raspberry Pi camera module  or USB camera module. The TrafficHat class from gpiozero will allow us to easily manipulate the TrafficHAT board. And the imutils library will be used for some OpenCV convenience functions.

If you don’t already have imutils installed, let pip install it for you:

$ pipinstallimutils

Lines 12-17parse our command line arguments. The first argument, -- picamera is used to indicate whether or not the Raspberry Pi camera module should be used. By default, a USB webcam is assumed to be connected to the Pi. But if you want to use the Raspberry Pi camera module instead, simply supply -- picamera 1 as a command line argument. The second switch, -- log , is used to control the path to the output log file which can be used for debugging.

Our next code block handles performing a series of initializations, including accessing the VideoStream class and setting up the TrafficHat module:

# open the logging file
logging.basicConfig(filename=args["log"], level=logging.DEBUG)
 
# initialize the video stream and allow the cammera sensor to
# warmup
logging.info("[{}] waiting for camera to warmup".format(
 datetime.datetime.now()))
vs = VideoStream(usePiCamera=args["picamera"] > 0).start()
time.sleep(2.0)
 
# define the lower and upper boundaries of the "green"
# ball in the HSV color space
greenLower = (29, 86, 6)
greenUpper = (64, 255, 255)
 
# initialize the TrafficHat and whether or not the LED is on
th = TrafficHat()
ledOn = False

We can now move on to the main video processing pipeline of our script, where we read frames from the VideoStream and process each of them, looking for a green ball:

# loop over the frames from the video stream
while True:
 # grab the next frame from the video stream, resize the
 # frame, and convert it to the HSV color space
 frame = vs.read()
 frame = imutils.resize(frame, width=500)
 hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
 
 # construct a mask for the color "green", then perform
 # a series of dilations and erosions to remove any small
 # blobs left in the mask
 mask = cv2.inRange(hsv, greenLower, greenUpper)
 mask = cv2.erode(mask, None, iterations=2)
 mask = cv2.dilate(mask, None, iterations=2)
 
 # find contours in the mask and initialize the current
 # (x, y) center of the ball
 cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
 cv2.CHAIN_APPROX_SIMPLE)
 cnts = cnts[0] if imutils.is_cv2() else cnts[1]
 center = None

If we find the green ball, then we’ll buzz the buzzer and light up the green LED on the TrafficHAT:

 # only proceed if at least one contour was found
 if len(cnts) > 0:
 # find the largest contour in the mask, then use
 # it to compute the minimum enclosing circle and
 # centroid
 c = max(cnts, key=cv2.contourArea)
 ((x, y), radius) = cv2.minEnclosingCircle(c)
 M = cv2.moments(c)
 center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
 
 # only proceed if the radius meets a minimum size
 if radius > 10:
 # draw the circle and centroid on the frame
 cv2.circle(frame, (int(x), int(y)), int(radius),
 (0, 255, 255), 2)
 cv2.circle(frame, center, 5, (0, 0, 255), -1)
 
 # if the led is not already on, raise an alarm and
 # turn the LED on
 if not ledOn:
 logging.info("[{}] alarm ON".format(
 datetime.datetime.now()))
 th.buzzer.blink(0.1, 0.1, 10, background=True)
 th.lights.green.on()
 ledOn = True

Finally, if the green ball is not found, we’ll turn off the LED on the TrafficHAT:

 # if the ball is not detected, turn off the LED
 elif ledOn:
 logging.info("[{}] alarm OFF".format(
 datetime.datetime.now()))
 th.lights.green.off()
 ledOn = False
 
# do a bit of cleanup
logging.info("[{}] cleaning up".format(
 datetime.datetime.now()))

Again, for a more comprehensive review of this code, please refer to last week’s blog post .

Assuming you’ve read through last week’s post, you might notice an interesting modification — I’ve removed the call to cv2 . imshow , which is used to display output frames to our screen.

Why would I do this?

Mainly because our pi_reboot_alarm . py script is meant to run in the  background when our Pi is rebooted — the output is  never meant to be displayed to our screen. All we care about is the alarm being properly raised if the green ball enters our video stream.

Furthermore, removing calls to cv2 . imshow reduces I/O latency, thereby allowing our Python script to run  faster and process frames  quicker (you can read more about I/O latency related to video streams in this post ).

Executing a Python script at reboot

All that’s left to do now is test our crontab installation by rebooting our system. To restart my Raspberry Pi, I execute the following command:

$ sudoreboot

And as the following video demonstrates, as soon as my Pi boots up, the on_reboot . sh shell script is called, thereby executing the pi_reboot_alarm . py Python program and arming the alarm:

You can see from the following screenshot that once the green ball enters the view of the camera, the green LED of the TrafficHAT is illuminated:

Figure 5:An example of the alarm program running on Raspberry Pi after reboot, detecting the presence of the green ball, and then lighting up the green LED on the TrafficHAT board.

And if you watch the video above, you can also hear the buzzer going off at the same time.

Summary

In this blog post, I demonstrated how to use crontab to launch a Python + OpenCV script on reboot.

To accomplish this task, I utilized my Raspberry Pi; however, crontab is installed on nearly all Unix machines, so no matter if you’re on Linux or OSX, crontab is likely available for you to use .

Anyway, I hope you enjoyed this series of blog posts on utilizing the Raspberry Pi, OpenCV, and GPIO libraries. If you would like to see more blog posts about these topics, please leave a comment in the comments section at the bottom of this post.

And before you go, don’t forget to enter your email address in the form below to be notified when new blog posts are published!

Downloads:





About List