Title: Running a Python + OpenCV script on reboot - PyImageSearch

URL Source: https://pyimagesearch.com/2016/05/16/running-a-python-opencv-script-on-reboot/

Published Time: 2016-05-16T14:00:27+00:00

Markdown Content:
![Image 1: Figure 5: An example of the alarm programming running on Raspberry Pi reboot, detecting the presence of the green ball, and then lighting up the green LED on the TrafficHAT board.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20359'%3E%3C/svg%3E)

**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](http://www.cyberciti.biz/faq/linux-execute-cron-job-after-system-reboot/).

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.

![Image 2](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20128%20128'%3E%3C/svg%3E)

#### Looking for the source code to this post?

[Jump Right To The Downloads Section](#download-the-code)

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](https://pyimagesearch.com/2016/05/09/opencv-rpi-gpio-and-gpio-zero-on-the-raspberry-pi/), I demonstrated how to create an “alarm” program that detects this green ball in a video stream:

![Image 3: Figure 1: The green ball we will be detecting in our video stream. If the ball is found, we'll trigger an alarm by buzzing the buzzer and lighting up the green LED light.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20450'%3E%3C/svg%3E)

**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):

![Image 4: 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.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20450%20486'%3E%3C/svg%3E)

**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:

![Image 5: Figure 3: Notice how when the green ball is detected in the video stream, the LED on the TrafficHAT lights up.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20359'%3E%3C/svg%3E)

**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](https://pyimagesearch.com/opencv-tutorials-resources-guides/), 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
workon cv
cd /home/pi/pi-reboot
python pi\_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](https://pyimagesearch.com/2016/05/02/accessing-rpi-gpio-and-gpio-zero-with-opencv-python/)._

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](https://pyimagesearch.com/2016/05/02/accessing-rpi-gpio-and-gpio-zero-with-opencv-python/) and the [OpenCV, RPi.GPIO, and GPIO Zero on the Raspberry Pi post](https://pyimagesearch.com/2016/05/09/opencv-rpi-gpio-and-gpio-zero-on-the-raspberry-pi/)_ 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:

$ sudo crontab -e

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

![Image 6: Figure 4: An example of crontab file.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20375'%3E%3C/svg%3E)

**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](https://pyimagesearch.com/2016/05/09/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.video import VideoStream
from gpiozero import 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-9** handle 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](https://github.com/jrosebr1/imutils) will be used for some OpenCV convenience functions.

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

$ pip install imutils

**Lines 12-17** parse 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 = imutils.grab\_contours(cnts)
	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()))
cv2.destroyAllWindows()
vs.stop()

Again, for a more comprehensive review of this code, [please refer to last week’s blog post](https://pyimagesearch.com/2016/05/09/opencv-rpi-gpio-and-gpio-zero-on-the-raspberry-pi/).

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](https://pyimagesearch.com/2016/01/04/unifying-picamera-and-cv2-videocapture-into-a-single-class-with-opencv/)).

### 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:

$ sudo reboot

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:

![Image 7: Figure 5: An example of the alarm programming running on Raspberry Pi reboot, detecting the presence of the green ball, and then lighting up the green LED on the TrafficHAT board.](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20359'%3E%3C/svg%3E)

**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.

### What's next? We recommend [PyImageSearch University](https://pyimagesearch.com/pyimagesearch-university/?utm_source=blogPost&utm_medium=bottomBanner&utm_campaign=What%27s%20next%3F%20I%20recommend).

**Course information:**  
84 total classes • 114+ hours of on-demand code walkthrough videos • Last updated: February 2024  
★★★★★ 4.84 (128 Ratings) • 16,000+ Students Enrolled

**I strongly believe that if you had the right teacher you could _master_ computer vision and deep learning.**

Do you think learning computer vision and deep learning has to be time-consuming, overwhelming, and complicated? Or has to involve complex mathematics and equations? Or requires a degree in computer science?

That’s _not_ the case.

All you need to master computer vision and deep learning is for someone to explain things to you in _simple, intuitive_ terms. _And that’s exactly what I do_. My mission is to change education and how complex Artificial Intelligence topics are taught.

If you're serious about learning computer vision, your next stop should be PyImageSearch University, the most comprehensive computer vision, deep learning, and OpenCV course online today. Here you’ll learn how to _successfully_ and _confidently_ apply computer vision to your work, research, and projects. Join me in computer vision mastery.

**Inside PyImageSearch University you'll find:**

*   ✓ **84 courses** on essential computer vision, deep learning, and OpenCV topics
*   ✓ **84 Certificates** of Completion
*   ✓ **114+ hours** of on-demand video
*   ✓ **Brand new courses released _regularly_**, ensuring you can keep up with state-of-the-art techniques
*   ✓ **Pre-configured Jupyter Notebooks in Google Colab**
*   ✓ Run all code examples in your web browser — works on Windows, macOS, and Linux (no dev environment configuration required!)
*   ✓ Access to **centralized code repos for _all_ 536+ tutorials** on PyImageSearch
*   ✓ **Easy one-click downloads** for code, datasets, pre-trained models, etc.
*   ✓ **Access** on mobile, laptop, desktop, etc.

[Click here to join PyImageSearch University](https://pyimagesearch.com/pyimagesearch-university/?utm_source=blogPost&utm_medium=bottomBanner&utm_campaign=What%27s%20next%3F%20I%20recommend)

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!**

![Image 8](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20410%20567'%3E%3C/svg%3E)

#### Download the Source Code and FREE 17-page Resource Guide

Enter your email address below to get a .zip of the code and a **FREE 17-page Resource Guide on Computer Vision, OpenCV, and Deep Learning.** Inside you'll find my hand-picked tutorials, books, courses, and libraries to help you master CV and DL!