Running a Python + OpenCV script on reboot

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.

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 the ball is found, we'll trigger an alarm by buzzing the buzzer and lighting up the green LED light.

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.

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.

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 :

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:

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:

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

Figure 4: An example of crontab file.

Figure 4: An example of crontab file.

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

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:

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 will be used for some OpenCV convenience functions.

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

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:

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:

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

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

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:

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 programming running on Raspberry Pi reboot, detecting the presence of the green ball, and then lighting up the green LED on the TrafficHAT board.

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:

If you would like to download the code and images used in this post, please enter your email address in the form below. Not only will you get a .zip of the code, I’ll also send you a FREE 11-page Resource Guide on Computer Vision and Image Search Engines, including exclusive techniques that I don’t post on this blog! Sound good? If so, enter your email address and I’ll send you the code immediately!

, , , , ,

48 Responses to Running a Python + OpenCV script on reboot

  1. Atomek May 16, 2016 at 12:04 pm #

    That’s a useful tutorial, exactly what I needed right now. Great job!
    More articles on interfacing between OpenCV and GPIO would be welcome, e.g. working with a DC+Stepper Motor HAT which moves the camera to follow an object.
    Thanks!

    • Adrian Rosebrock May 17, 2016 at 11:36 am #

      Thanks Atomek! I don’t have a stepper motor/servo yet, that’s something I need to invest in. Do you have one that you’re already using that you can recommend?

      • Atomek May 18, 2016 at 12:29 pm #

        I’m using a 2 axis motor from car mirror. It’s supposed to required 12V but I’m running it straight from Raspberry’s USB 5V. It’s slower but that allows for more precision.
        http://www.ebay.co.uk/itm/261770579933

        • Adrian Rosebrock May 19, 2016 at 6:03 pm #

          Thanks for sharing 🙂

  2. Josh May 16, 2016 at 2:44 pm #

    Just a heads up, @reboot isn’t terribly reliable. Setting up an init script/systemd unit file (depending on OS version). Would be a much more reliable way of accomplishing what you’re looking for. With systemd you’d also get the free benefit of process monitoring and sane logging.

    • Adrian Rosebrock May 17, 2016 at 11:36 am #

      I (personally) don’t like systemd for this type of thing as this GIF jokes about. Upstart for Debian-based systems is also a good option.

  3. Lukas June 1, 2016 at 7:10 am #

    Hi,
    I wanted to share also a good option to start something on boot, called “supervisor” (install via “apt-get supervisor”). Very handy since you can start, stop, restart and get status of your running apps. I am using it for my RPI projects 😉

    • Adrian Rosebrock June 1, 2016 at 3:17 pm #

      Thanks for sharing Lukas!

  4. Kerem June 4, 2016 at 3:36 pm #

    Hi Adrian, for some reason I’m getting the following error when I manually call the on-reboot.sh to test it :

    /home/pi/pi-reboot/on_reboot.sh: line 3: workon: command not found

    my script is still running but it is not executing inside the virtual environment.

    When I type workon cv at the command prompt it runs without a problem and I can get into the virtual env.

    Any ideas what I might be missing here? Thanks much for all your guidance.

    • Adrian Rosebrock June 5, 2016 at 11:27 am #

      It sounds like your .profile file is not being source‘d before executing workon. Without running source /home/pi/.profile first, your system paths will not be setup correctly to find the workon command.

  5. Kerem June 5, 2016 at 8:42 pm #

    Hi Adrian, thanks for your kind reply. This is why I’m all confused.

    On the command prompt I use the following commands

    pi@Rpi3:~ $ source ~/.profile
    pi@Rpi3:~ $ workon cv
    (cv) pi@Rpi3:~ $ deactivate

    and as you will note I am able to get into the virtualenv without any trouble and then deactivate to come back out.

    My on_reboot.sh contents look like the following :

    #!/bin/bash
    source ~/.profile
    workon cv

    but when I execute this I get the workon: command not found error.

    So if I understand this correctly what you are suggesting is that the call to source ~/.profile in my script is not doing its job and as a result my system paths are not setup for the script to find the workon command.

    Funny thing is, as soon as I terminate the script and type workon at command prompt I am able to get workon to run.

    Hope this provides some hints as to what might be wrong in my environment. Many thanks for your amazing support.

    • Adrian Rosebrock June 7, 2016 at 3:29 pm #

      On reboot, your script is being executed as the root user, not the pi user. Therefore, you need to supply the full path to the .profile file:

      source /home/pi/.profile

      • Hai June 26, 2016 at 1:24 am #

        You can add your script executable command to the bottom of .bashrc that will run your script every time you log in.

        Make sure you are in the pi folder:
        $ cd ~
        Create a file and write a script to run in the file:
        $ sudo nano superscript
        Save and exit: Ctrl+X, Y, Enter
        Open up .bashrc for configuration:
        $ sudo nano .bashrc
        Scroll down to the bottom and add the line: ./superscript
        Save and exit: Ctrl+X, Y, Enter
        If you are looking for a solution that works on bootup to the console, take a look at this link. Basic rundown:

        Create a file for your startup script and write your script in the file:
        $ sudo nano /etc/init.d/superscript
        Save and exit: Ctrl+X, Y, Enter
        Make the script executable:
        $ sudo chmod 755 /etc/init.d/superscript
        Register script to be run at startup:
        $ sudo update-rc.d superscript defaults
        If you want a script to run when you boot into the LXDE environment, you could take a look at this Raspberry Pi forum post:

        Navigate to etc/xdg/lxsession/LXDE-pi
        Open the autostart file in that folder:
        $ sudo nano autostart
        Add @midori on a new line. If you want to run something like a python script, put something like @python mypython.py on a new line. Running a script file would be @./superscript, but for some reason the script runs in an infinite loop (perhaps this will stop that).
        Save and exit: Ctrl+X, Y, Enter
        Restart your Raspberry Pi into the LXDE environment.
        http://raspberrypi.stackexchange.com/questions/8734/execute-script-on-start-up

        • Adrian Rosebrock June 28, 2016 at 11:01 am #

          Awesome, thanks so much for sharing Hai!

      • Jeck September 7, 2016 at 3:24 pm #

        I have the same prob as kerem. I followed your installation tutorial for pi 3 + opencv + python. I ran the on_reboot.sh in root in order to emulate what happens during boot. The results were the same as kerem said. It seems we are only able to go to our opencv virtual env after logging in (not in root). How are you able to go to your virtual environment while still in root?

        PS. I also made a log directory so i can see errors during boot. The resulting error messages were the same as the one generated by the one above

        • Adrian Rosebrock September 8, 2016 at 1:20 pm #

          You can still access your Python virtual environment while in the root account. For example, if I wanted to launch a root shell and access my virtual environment from the “pi” account, all I would need to do is:

          And from there, you can access the cv virtual environment as the root user. You can apply the same technique to your shell scripts that are launched on boot as well.

          • Jeck September 13, 2016 at 7:43 am #

            thanks for the reply. but unfortunately it didn’t work. once I typed workon cv. an error has occured.

            ERROR: Environment ‘cv’ does not exist. Create it with ‘mkvirtualenv cv’.
            root@raspberrypi:/home/pi#

          • Adrian Rosebrock September 13, 2016 at 12:49 pm #

            If the cv virtual environment doesn’t exist, then you may have installed OpenCV without Python virtual environments. That’s totally okay, but you’ll need to manually debug the issue. Please note that I can only support OpenCV install questions if you followed one of my OpenCV install tutorials.

  6. Hai June 26, 2016 at 1:26 am #

    Run it In terminal : bash yourscript.sh

    • Adrian Rosebrock June 28, 2016 at 11:01 am #

      If the script is already executable, you could also do:

      $ ./yourscript.sh

  7. ghanendra July 14, 2016 at 3:40 am #

    Hey Adrian how to open tkinter gui on startup?? . I ‘m using vncserver to execute the script

    • Adrian Rosebrock July 14, 2016 at 1:09 pm #

      So your goal is to boot up your Pi, have it automatically launch the GUI interface, and then at the same time open your TKinter GUI script?

      • ghanendra July 17, 2016 at 1:34 pm #

        On boot up, Pi launches with GUI interface, only how to open Tkinter GUI script?

        • Adrian Rosebrock July 18, 2016 at 5:14 pm #

          I personally haven’t tried this before, but I imagine you could accomplish this by editing your .xinitrc file.

  8. Emrah August 22, 2016 at 1:53 am #

    Dear Adrian

    I had started learning OpenCV with your book about 2 years ago. Now, It is quite amazing to see how you constantly enhanced your courses/blog posts according to industry and our needs over the past years.

    And again, you sensed our needs quite accurately by publishing this crontab tutorial.

    • Adrian Rosebrock August 22, 2016 at 1:26 pm #

      Thank you for the kind words Emrah! 🙂

  9. ishant December 10, 2016 at 6:11 pm #

    hello adrian
    i followed your steps, i checked it after bash filename.sh but after reboot its not running

    • Adrian Rosebrock December 12, 2016 at 10:45 am #

      Hey Ishant — it’s hard to tell what the exact issue may be on your machine without having access to it. Take a look at my reply to “Luis Lopez” above for suggestions on how to debug the script.

  10. luis lopez December 11, 2016 at 9:17 pm #

    hey adrian, first of all thank you for all the help you provide us, i have learned a lot from you and i just want you to know that you are a great teacher and person.

    Now, I have a problem with one script, I did everything you said in this lesson and it works just fine when I reboot except with one script that does nothing after the reboot reboot, it’s the only one that does this and the only difference between this script and the others is that I use the skfuzzy library, do you think this has something to do? or how can i check whats wrong?.

    Again thanks for everything.

    • Adrian Rosebrock December 12, 2016 at 10:28 am #

      I would suggest inserting as many logging statements into your script as possible. Have the script write to a file you can monitor (like using print statements to debug). You may have forgotten to install skfuzzy into your virtual environment and the script could be throwing an error when trying to import it (hence the script not running). That’s just a best guess though.

  11. Dua December 21, 2016 at 7:43 am #

    Hello, and thank you a lot for this lesson.
    I have done exactly what you have instructed in this tutorial, and when I tested the on_reboot.sh file from the terminal it worked out perfectly. But unfortunately when I reboot the Pi nothing happens. I added the line on crontab file and everything, but still nothing is happening when I reboot. Do you have any idea why is this happening?
    thank you,

    • Adrian Rosebrock December 21, 2016 at 10:19 am #

      It’s hard to say without having physical access to your machine. I would suggest inserting some echo calls that log to file inside on_reboot.sh to help determine if on_reboot.sh is actually being called. There might be an error in your crontab entry.

  12. ANAS MUBARAK January 31, 2017 at 6:31 am #

    Gtk-WARNING **; cannot open display : on log while running above

    • Adrian Rosebrock February 1, 2017 at 12:57 pm #

      It sounds like you’re trying to use cv2.imshow in your Python reboot script. This will not work since the script is running in the background. Remove the call to cv2.imshow and your script should work.

  13. Melrick Nicolas March 4, 2017 at 2:26 am #

    hi adrian , i made a cronlog to know the what is happening and i found out tha the error says
    (opencv:523):gtk -warning **:can not open display:
    what do you think happen?
    tnx for your tutorial

    • Adrian Rosebrock March 4, 2017 at 9:34 am #

      Are you calling cv2.imshow from your cronjob? That won’t work. The cronjob runs in the background and does not have access to the display.

  14. sahil March 21, 2017 at 8:28 am #

    will this work for home surveillance system shown in other tutorial?
    do i need to remove cv2.imshow part ?
    and how to wait before pi is connected to internet after rebooting for dropbox access?
    plz reply..

    • Adrian Rosebrock March 22, 2017 at 8:47 am #

      Yes, make sure you remove the cv2.imshow calls so that script simply runs in the background.

      • sahil March 23, 2017 at 10:07 am #

        will it be connected to internet before execution of code or show error?

        • Adrian Rosebrock March 25, 2017 at 9:39 am #

          That is hard to say as you cannot guarantee an internet connection (invalid WiFi password, network down, etc.) You would want to add extra logic to ensure your Raspberry Pi is connected to the internet if that is possible. The easiest way to do this would be via a shell script rather than trying to code it in Python.

          • sahil April 19, 2017 at 5:41 am #

            thank you sir

  15. David Steele May 4, 2017 at 6:42 pm #

    Adrian,
    Thanks for the good advice. I was using the cv2.imshow in the python script that was called on reboot and I was getting the GTK Error. I need to have the image display to work on reboot. Please advise where I can find the procedure to display the cv2.imshow image after reboot.

    • Adrian Rosebrock May 8, 2017 at 12:42 pm #

      A Python script executed in the background does not have access to the window manager, hence the GTK error. I would suggest updating your Pi such that the pi user is automatically logged into the Raspberry Pi and the window manager started. From there you should be able to update your ~/.profile file to automatically launch the script.

  16. albert June 27, 2017 at 12:03 pm #

    Hi Adrian, my script works/environment works normally when manually run(im using your preinstalled py3cv3 environment). But when i try and run it with crontab with @reboot it throws the error of

    Traceback (most recent call last):
    File “reboot.py”, line 2, in
    from imutils.video import VideoStream
    ImportError: No module named imutils.video

    the environment i’m using has imultils installed and i can run it manually but am not sure why it’s not running with @reboot??
    Any hints you have would be really good, thanks!

  17. albert June 27, 2017 at 2:24 pm #

    Thanks Adrian for the tutorials, really detailed and useful!

    Just to add an alternative method, i had trouble starting the virtual environment with the workon command, with many imports like cv2 or imutils not being found. I managed to get around this using this startup script instead:

    #!/bin/bash
    . /home/pi/.virtualenvs/py3cv3/bin/activate

    cd /home/pi/Scripts/
    python videoSave.py >> /home/pi/on-reboot/feedback.log 2>&1

    deactivate
    cd /home/pi

    Hope this is helpful

    • Adrian Rosebrock June 30, 2017 at 8:28 am #

      Thank you for sharing Albert!

  18. William July 2, 2017 at 6:25 pm #

    my crontab is empty. I have been trying to run @reboot python /home/pi/reboot8.py. This script looks for an input on GPIO to reboot the Rpi in case of lost remote control ie., other side of the planet. I placed that statement in my crontab anyway but doesn’t take. Your instruction go from optional cv to running a cv script anyway. A little guidance please, old brains aren’t as quick the youngins.

    Thanks

    • Adrian Rosebrock July 5, 2017 at 6:20 am #

      Hi William — thanks for the comment, although I’m not sure what your exact question is? It sounds like you are trying to edit your crontab file but it is always empty? Are you making sure to save and exit the editor?

Leave a Reply