Accessing RPi.GPIO and GPIO Zero with OpenCV + Python

Figure 5: A second example of using OpenCV to display an image and then utilizing GPIO to illuminate an LED.

I can’t believe this is the first time I am writing a blog post on GPIO and the Raspberry Pi. It’s a pretty big mistake on my part. I should have written this post much earlier.

You see, on average, I receive 1-3 emails per week along the lines of:

When I use the ‘cv’ virtual environment, I can access my OpenCV bindings. But then I can’t import RPi.GPIO. When I switch out of the virtual environment (and use the system Python), I can use RPi.GPIO, but I can’t import OpenCV. What gives?

The reason for this problem is that RPi.GPIO/GPIO Zero were not installed into your Python virtual environment! To fix this issue, all you need to do is use pip  to install them into your virtual environment — from there, you’ll be good to go.

But to be honest with you, I don’t think that’s the real issue here!

The real problem is not having a sufficient understanding of what Python virtual environments are and why we use them. Utilizing Python virtual environments is a best practice that you need to become comfortable with.

In the remainder of this blog post, I’ll gently introduce the concept of Python virtual environments. And from there, we’ll learn how to install RPi.GPIO and GPIO Zero into the same Python virtual environment as our OpenCV bindings, allowing us to access both OpenCV and RPi.GPIO/GPIO Zero at the same time!

Keep reading to find out how…

Looking for the source code to this post?
Jump right to the downloads section.

Accessing RPi.GPIO and GPIO Zero with OpenCV + Python

Before we learn how to (correctly) install RPi.GPIO and GPIO Zero on our Raspberry Pi, we first need to review the concept of Python virtual environments.

If you’ve ever followed one of the Raspberry Pi + OpenCV install tutorials on the PyImageSearch blog, you’ll know that I’m a huge fan of Python virtual environments and recommend them for nearly every project.

However, it seems that I haven’t done a good enough job explaining what Python virtual environments are and why we use them. The following section should help clear up any questions.

What are Python virtual environments?

At the very core, Python virtual environments allow us to create isolated, independent environments for each of our Python projects. This implies that each project can have its own set of dependenciesregardless of which dependencies another project has.

So why in the world would we want to create a virtual environment for each of our projects?

Consider this: Suppose we are software contractors and are hired by a company to develop ProjectA. But before we have completed ProjectA, a second company hires us to develop ProjectB. We notice that both ProjectA and ProjectB have a dependency on LibraryAbut the problem is that ProjectA requires v1.0.0 of LibraryA while ProjectB requires v2.0.0!

This is a real issue for Python because we cannot install two different versions of the same library into the same site-packages  directory (i.e., where Python stores 3rd party libraries, such as the ones you download and install from pip , GitHub, etc.).

So, what do we do?

Do we run out to the nearest Apple Store and buy a new MacBook Pro so we can use one laptop to develop ProjectA and the other to develop ProjectBI really hope not. That would get expensive quick.

Do use a web host like Linode, Digital Ocean, or Amazon EC2 and spin-up a new instance for each project? This is a better solution, and is highly applicable in some cases, but in our specific instance, it’s overkill.

Or do we use Python virtual environments?

You guessed it — we go with Python virtual environments.

In this case, all we need to do is create a virtual environment for each project, that way there is a separate, isolated, and independent environment for all projects:

Figure 1: Each Python environment we create is separate and independent from the others.

Figure 1: Each Python environment we create is separate and independent from the others.

This allows us to install completely different dependencies for ProjectA and ProjectB, ensuring we can finish development of both projects on the same computer.

Pretty neat, right?

Of course, there are many more benefits to using Python virtual environments, but instead of listing them all out, please refer to this excellent Python virtual environments primer on the RealPython blog.

But Adrian, I’m already using Python virtual environments!

If you followed any of the OpenCV install tutorials on the PyImageSearch blog, then you’re already using Python virtual environments.

So how can you find out for sure?

If you need to execute workon <virtual environment name>  before executing your Python script to import OpenCV, then guess what, you’re using Python virtual environments.

But here is the real problem…

You probably installed RPi.GPIO and GPIO Zero incorrectly

“Incorrect” is the wrong word to use here — but I needed to get your attention. When you went to install RPi.GPIO or GPIO Zero, I’m willing to bet you used apt-get . Your command probably looked (something) like this:

This command will download RPi.GPIO and GPIO Zero from the official Raspbian package repository and install them on your system.

The problem is that apt-get  will install packages into the system install of Python and not your Python virtual environments.

And this is exactly why you run into problems like:

I can import OpenCV in the ‘cv’ virtual environment, but I can’t import RPi.GPIO. On the other hand, I can import RPi.GPIO outside of the ‘cv’ environment, but then I can’t import cv2.

How do you resolve this issue?

You just need to install your libraries into your virtual environment rather than the system version of Python, which can easily be accomplished by workon  and pip .

This brings me to my next point:

do not recommend using apt-get  to install Python libraries.

You’re probably thinking, “But Adrian, using apt-get  is so easy! It’s just one command and then I’m done!”

I’ve got news for you — using pip  is also one command. And it’s just as easy.

To get back to my point, not only will apt-get  install these libraries into the system Python (rather than your virtual environment), there is also the issue that apt-get  packages are normally a bit out of date.

And guess what happens when you want to install the newest version of a given library?

Hint: You run into the exact problem detailed above — you’ll be trying to install two different versions of the same library into the same site-packages  directory, which simply cannot happen (due to how Python works).

Instead, you should be using the Python package manager, pip, to install your Python packages into virtual environments. For more information on pip , how it works, and why we use it, please refer to this article.

Installing RPi.GPIO and GPIO Zero “correctly”

Let’s go ahead and get RPi.GPIO and GPIO zero installed  into our Python virtual environment. To start, first use the workon  command to enter your Python virtual environment:

Note: You may need to execute source ~/.profile  prior to running the workon  command so that the virtual environment startup scripts are loaded.

You can tell you are in a Python virtual environment if the name of the environment appears in parenthesis before your prompt:

Figure 2: I can tell I am in the "cv" virtual environment because I can see the text "(cv)" before my prompt.

Figure 2: I can tell I am in the “cv” virtual environment because I can see the text “(cv)” before my prompt.

In this case, I have entered the cv  virtual environment and I can verify this because I see the text “(cv)” before my prompt.

From there, we can let pip  install RPi.GPIO and GPIO Zero for us:

Lastly, let’s test the install and ensure we can import RPi.GPIO, GPIO Zero, and OpenCV together:

Note: I’ve made the assumption that the virtual environment you are using already has OpenCV installed in it. My cv  virtual environment has OpenCV already installed, so by using pip  to install the RPi.GPIO  and gpiozero  to install the respective GPIO packages, I’m able to access all three libraries from within the same environment.

Once you can import these libraries in the same environment, we’re ready to move on.


For this blog post, I used my Raspberry Pi 3 and the TrafficHAT board, a really cool module for the Raspberry Pi that allows you to get started quickly and easily with GPIO programming:

Figure 3: 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 3: The TrafficHAT module for the Raspberry Pi, which includes 3 LED lights, a buzzer, and push button, all of which are programmable via GPIO.

As you can see, the TrafficHAT includes 3 big LED lights, a push-button, and a buzzer.

Note: It’s called a “hat” because we simply need to set it on top of the GPIO pins — no breakout board, extra cables, or soldering is required.

Once we have the TrafficHAT installed on the Raspberry Pi, we can program it using nearly any programming language (provided the language can access the GPIO pins), but for the purposes of this blog post, we’ll be using Python + RPi.GPIO and GPIO Zero.

Using RPi.GPIO + OpenCV

Let’s go ahead and write some code to access the TrafficHAT board using the RPi.GPIO library. We’ll also utilize OpenCV to load an image from file and display it to our screen.

Open up a new file, name it , and insert the following code:

Lines 2-4 handle importing our required Python packages. We then load the input image from disk and display it to our screen on Lines 8-10. Our script will pause execution until we click on the active image window and press any key on our keyboard.

From there, we loop over each of the LEDs on the TrafficHAT (Line 18). For each of these lights, we:

  1. Turn the LED light on.
  2. Wait 3 seconds.
  3. Turn the light off and continue looping.

To execute , make sure you are in the cv  virtual environment (or whatever virtual environment you are using to store your OpenCV bindings + GPIO libraries) by using the workon  command:

We can then run the  script:

As the output image demonstrates, we can see that our hoover_dam.jpg  image is displayed to the screen and the green LED lights is shining brightly on the TrafficHAT:

Figure 4: Loading an image to my screen using OpenCV and then lighting up the green LED using GPIO.

Figure 4: Loading an image to my screen using OpenCV and then lighting up the green LED using GPIO.

What about root?

But what if we wanted to execute  as the root user? What do we do then?

We have two options here.

The first option is to use the sudo  command inside our Python virtual environment, like this:

Note: Make sure you are in your Python virtual environment before executing your script with sudo ; otherwise, you will not have access to the libraries installed in your virtual environment.

The second option is to launch a root shell, access our Python virtual environment, and then execute the script:

Which one is best?

To be honest, it doesn’t really matter.

There are some cases where using sudo  is easier. And there are others where it’s nice to simply have a root shell pulled up. Use whichever option you’re more comfortable with — just be careful when executing commands as root!

Using RPI Zero + OpenCV

Now that we’ve explored RPi.GPIO, let’s re-create the same Python script, but this time using the GPIO Zero library. Open up a different file, name it , and insert the following code:

Lines 2-4 again handle importing our required packages. What’s really interesting here is that the gpiozero  library has a TrafficHat  class, which enables us to easily interface with the TrafficHAT module.

Lines 8-10 handle loading and displaying our input image to sour screen.

We can then initialize the TrafficHat  object and construct the list of lights  on Lines 14 and 15.

Finally, Lines 18-21 handle looping over each of the lights , turning each on individually, waiting 3 seconds, and then turning the light  off before moving to the next one.

Just like the RPi.GPIO example, we first need to access our Python virtual environment and then execute our script:

As the script executes, we can see an image displayed to our screen and the LEDs lighting up:

Figure 5: A second example of using OpenCV to display an image and then utilizing GPIO to illuminate an LED.

Figure 5: A second example of using OpenCV to display an image and then utilizing GPIO to illuminate an LED.

Note: To execute this script as root, follow the instructions detailed in the previous section.


In this blog post, I started by reviewing what Python virtual environments are and why we use them. Simply put, Python virtual environments allow us to create independent, isolated development environments for each project we work on, ensuring we don’t run into version dependency issues. Furthermore, virtual environments allow us to keep our system install of Python clean and tidy.

Once we understood the basics of Python virtual environments, I detailed how to (correctly) install RPi.GPIO and GPIO Zero such that we can access both GPIO libraries and OpenCV at the same time.

We then developed a simple Python script that loads an image from disk using OpenCV, displays it to our screen, and then lights up various LEDs on the TrafficHAT.

In the next blog post, we’ll create a more advanced GPIO + OpenCV script, this time lighting up LEDs and buzzing the buzzer whenever a pre-defined visual action takes place.

Be sure to enter your email address in the form below to be notified when the next blog post goes live, you won’t want to miss it!


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 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! Sound good? If so, enter your email address and I’ll send you the code immediately!

, , , ,

46 Responses to Accessing RPi.GPIO and GPIO Zero with OpenCV + Python

  1. Bryce Williams May 8, 2016 at 4:29 pm #

    I think it would be awesome to talk about cloning virtualenv’s (maybe somthing along the lines of using virtualenv-clone). I like to have a pristine pcv/Python virtualenv i can use as a base for other projects. Otherwise it takes a minute to get all the python bindings setup.

    I am so glad I found your website, it has opened a whole new world of programming possibilities. I’m currently attempting to use OpenCV3 and Python to scan, OCR and then upload the data to the web 🙂

    • Adrian Rosebrock May 9, 2016 at 6:59 pm #

      Thanks for the suggestion Bryce!

  2. Arasch U Lagies May 15, 2016 at 2:45 am #

    Hi Adrian,
    Thanks for the great tutorial.
    For some reason if I run the script as sudo I get “ImportError: No module named RPi.GPIO”. Even though going into the python shell and trying “import RPi.GPIO” shows no issues.
    Only if I use your second option to launch a root shell with “sudo /bin/bash, etc.” the GPIO routine works.
    Generally this would be ok, but I would like to write the program call into crontab so that the GPIO’s are accessed in regular time intervals.
    Any idea what the problem could be? Thanks for any suggestions.

    • Adrian Rosebrock May 15, 2016 at 11:03 am #

      If you would like to use crontab to execute a Python at regular intervals, keep an eye on next week’s blog post where I demonstrate how to use crontab to execute a Python + OpenCV script on reboot. The same principle can be applied to running cronjobs at regular intervals as well.

  3. Melrick Nicolas October 19, 2016 at 3:46 am #

    how can i install serial module? when i import serial the error says”No Module Named Serial”
    but when i install it using pip install serial the error says “no matching distribution found for serial”

    • Adrian Rosebrock October 20, 2016 at 8:45 am #

      I think the actual name of the package is “pyserial”:

      $ pip install pyserial

  4. Priyal Aggarwal December 23, 2016 at 11:50 pm #

    Thanks for all the great posts Adrian. Your blog is my goto place for all things related to Computer Vision. The first half of this post helped me understand how to install pygame on Ubuntu and saved my day!

    • Adrian Rosebrock December 31, 2016 at 1:50 pm #

      Thank you for the kind words Priyal, I’m happy I could help out 🙂

  5. Ben Nuttall January 23, 2017 at 3:24 pm #

    FYI – th.lights is a property containing all three lights in a TrafficLights object, which you can iterate over like you do in your example:

    • Ben Nuttall January 23, 2017 at 3:25 pm #

      Mistake in above comment – can you change to for light in th.lights? (sorry)

  6. Rossi January 27, 2017 at 2:02 pm #

    Hey Adrian.
    First of all, I’d like to thank you for all your support throught your page. I had a problem and aI hope you could help me.
    I’m developing a recogning face system using OpenCV and Raspberry Pi for my final project to graduate in Automation Engineering.
    Thus, I wrote a simple code in the final of my recogning code in order to use the GPIO, but when I execute using the Python environment, the following message showed: “RuntimeError: No access to /dev/mem. Try running as root!”.
    So, I read your page and I used before “python” the word “sudo”, as you adviced. But, appeared the message: “ImportError: No module named cv2”.
    As you said, there is other way to run the code as root. Therefore, still in python environment,I typed “sudo /bin/bash” and the root changed for: “root@raspberrypi:” in write words. In following, I put “/home/pi/.profile”, but, when I typed “work cv” appeared the message: “ERROR: Environment ‘cv’ does not exist. Create it with ‘mkvirtualenv cv'”.
    Would you have a way to help me? I don’t find anything that I could use to solve this problem.
    Thank you again.

    • Adrian Rosebrock January 28, 2017 at 8:54 am #

      If the method I suggested isn’t working, the alternate method is to specify the full path to the Python binary inside the virtual environment directory. This will ensure the correct environment variables are used. For example, you can do this:

      $ sudo ~/.virtualenvs//bin/python

      Just replace env_name with the name of your Python virtual environment.

      • Rossi January 30, 2017 at 4:45 pm #

        It worked perfectly Adrian. Thank you so much.

        • Adrian Rosebrock February 1, 2017 at 1:00 pm #

          Fantastic, glad to hear it 🙂

  7. varalakshmi March 1, 2017 at 2:22 am #

    how can i install motion sensor library with opencv in python for raspberry pi.. will any one please help me out

    • Adrian Rosebrock March 2, 2017 at 6:52 am #

      What is the “sensor” library? Can you provide a link to it?

  8. Akm June 7, 2017 at 4:13 pm #

    Nice blog. I have 1 query – In my virtualenv, I need to use sudo for all commands. How do I achieve this?

    • Adrian Rosebrock June 9, 2017 at 1:47 pm #

      Please see the “What about root?” section of this blog post as it directly addresses your question.

  9. Petes June 16, 2017 at 12:30 pm #

    I’m trying to install rpi.gpio and gpiozero in libreelec but apt-get is disabled. I managed to install it from the default Programs by installing Raspberry Pi Tools but when I try to run the commands I get the Not Found message like if they didn’t get installed, any idea? I’m using libreelec 7.0.3 (Jarvis).

    • Adrian Rosebrock June 20, 2017 at 11:20 am #

      Hi Petes — I’m not sure what “libreelec” is. Why do you not have access to apt-get?

  10. James Morgenson September 24, 2017 at 9:44 pm #

    Is there a quick way to install OpenCV to the general environment or to another virtual environment once it’s been compiled for the cv virtual environment?

    • Adrian Rosebrock September 26, 2017 at 8:32 am #

      Can you elaborate on what you mean by “general environment”? Do you mean the system install of Python?

  11. Bogdan December 9, 2017 at 1:29 am #

    Thank you.

  12. Neil January 18, 2018 at 1:03 pm #

    Hi Adrian.

    It’s all good stuff!

    Is there a way to enter the environment from python using say, Popen? Something like:
    Inv = Popen(“sudo ~/.py2cv3//bin/home/pi/python”)

    Many thanks

    • Adrian Rosebrock January 19, 2018 at 6:47 am #

      Hey Neil — there are a number of ways to do this, some easy, some complicated. You can skip the workon command directly if you call the full path to the Python binary (as you are doing):

      os.system("sudo ~/.py2cv3//bin/home/pi/python")

      But you’ll need to supply the full path each time you want to execute the script. Maintaining an actual state (like a shell/terminal) is tricky and should be avoided if you can.

  13. fernando January 26, 2018 at 10:05 am #

    Hi Adrian, now I am working on Facial Recognizer system using python and opencv i have a problem when the usb camera capture video recognize my face the system must turn on a led for around 3-4 seconds and later turn off the led, but when i use time.sleep the whole program stops for 3-4 seconds and video is so slow, how can resolve this problem my mail is (email removed by spam filter) ,it does not matter if I have to pay some money for this because is my final project.
    Please answer.

    • Adrian Rosebrock January 26, 2018 at 10:20 am #

      Hey Fernando — if this is your final project I would recommend you implementing it yourself. I will not accept payment for doing your project and I hope others would not accept payment (or do the project for you) as well. We learn by putting in the hard work and learning from experiences. Through our struggles we learn new techniques. Keep in mind that your diploma is just a piece a paper. Your real education comes from fighting through the challenging moments.

      All that said, if you can describe your project in more detail and explain what the problem is (again, in more detail) that would be helpful. The LED normally indicates that the camera is on. If the LED is off, then your camera is in all likelihood off as well. This could be due to a logic issue in your code.

  14. Ali February 5, 2018 at 11:29 am #

    Hello Adrian,

    Thanks for all your great tutorials! I have a project that involves opencv on a raspberry pi and turning on and off fans when a red color is detected. I have been able to implement the red color detection on the pi thanks to your tutorials. But I have a problem with the GPIO setup. I have used pip install GPIO on my virtual environment. However, when I run my code to turn the fan ons using a relay, it does not work in the virtual environment. I don’t have any errors or anything and it seems like the library imports properly. However, it does work when I run a simple on-off script on the systems python. Do you happen to know what might be wrong?

    • Adrian Rosebrock February 6, 2018 at 10:12 am #

      Hm, that is quite strange. Unfortunately I’m not sure what the problem may be, Ali. Have you verified that you can control the GPIO pins from outside the Python virtual environment?

      • Ali February 6, 2018 at 2:03 pm #

        Yes. I was able to control the GPIO pins from the systems python3. The only difference that I can think of is that I am controlling the GPIO pins from outside the virtual environment using Python 3. My virtual environment with opencv is running Python 2. Do you think it’s worth it to try to install opencv in a python3 virtual environment? that will take me many hours and I am trying to avoid that. haha!

        • Adrian Rosebrock February 8, 2018 at 8:44 am #

          Which commands did you use to install the GPIO libraries on the system Python? Also, could you be a bit more clear about what you mean by the script does not work within the Python virtual environment? You’re able to import your OpenCV + GPIO libraries but the script just automatically exits when trying to access a video stream? I’m not clear on what “doesn’t work” in this context means.

          • Ali February 8, 2018 at 5:59 pm #

            So I just fixed it. I was frustrated so I thought I just uninstall and install the GPIO package again. I ran pip uninstall RPi.GPIO. and then pip install RPi.GPIO. now it’s working. Thank you very much!

          • Adrian Rosebrock February 12, 2018 at 6:42 pm #

            Nice, congrats on resolving the issue, Ali!

  15. Rajnish kumar June 1, 2018 at 3:45 am #

    Hello sir

    I have issues related to choosing and accessing button using eye motion when my eye motion is to right or left and my GUI is designed in python qt .Please help me for this issue how can i use eye motion for choosing and accessing my button.

    • Adrian Rosebrock June 5, 2018 at 8:27 am #

      Hey Rajnish, thanks for the comment. However, I do not have any tutorials or detecting eye movement and then using the movement to move the mouse on your computer. I will consider it for a future tutorial though!

  16. Gabriela September 29, 2018 at 4:36 pm #

    Hi Adrian, Do you know how can I run a script in a virtual environment automatic when the raspberry is power on?

  17. Brad January 11, 2019 at 8:39 am #

    I’m new to Python and have been editing my scripts using Thonny. To test a script, I simply hit the green “play” button. When running a script from an IDE, how do I control which virtual environment is being used?

    • Adrian Rosebrock January 11, 2019 at 9:24 am #

      I don’t have any experience with Thonny but from what I know it does not support Python virtual environments. Can you execute the code via command line instead?

  18. THILAI THILA January 19, 2019 at 8:06 am #

    i need to capture a circle object from a live cam and then turn on an LED light using GPIO pins if the object is detected. how should i do that? Please guide me, thank you adrian

  19. Aaron Casipit March 31, 2019 at 10:48 pm #

    How if there is no pip install version of the library? Like this one . I really need help thankyou so much for your time,

  20. Ambujaksh shah April 13, 2019 at 5:00 am #

    Hi Adrian,

    I am having a issue as i want to run a script at the time of start up and the working of the script is to display logo as i also using pir motion sensor so when any kind of motion detected camera start capturing.
    As you told in your tutorial Running a Python + OpenCV script on reboot i have done the same but nothing happens then to check that is script is loaded on startup or not i append a small script of led blinking at the starting of the script and on reboot it work fine but logo is not displayed. So please guide me where i am wrong..

    • Adrian Rosebrock April 18, 2019 at 7:38 am #

      Do you want your Python script to run in the background? Or run in the foreground of the GUI?

  21. Ryan July 1, 2019 at 4:17 pm #

    Thank you immensely for everything you’ve published thus far.

    Do you have any tutorials or examples of simple code utilizing openCV with either RPi.GPIO or gpiozero that DOESN’T use TrafficHAT?


  1. OpenCV, RPi.GPIO, and GPIO Zero on the Raspberry Pi - PyImageSearch - May 9, 2016

    […] Last week we learned a bit about Python virtual environments and how to access the RPi.GPIO and GPIO Zero libraries along with OpenCV. […]

Before you leave a comment...

Hey, Adrian here, author of the PyImageSearch blog. I'd love to hear from you, but before you submit a comment, please follow these guidelines:

  1. If you have a question, read the comments first. You should also search this page (i.e., ctrl + f) for keywords related to your question. It's likely that I have already addressed your question in the comments.
  2. If you are copying and pasting code/terminal output, please don't. Reviewing another programmers’ code is a very time consuming and tedious task, and due to the volume of emails and contact requests I receive, I simply cannot do it.
  3. Be respectful of the space. I put a lot of my own personal time into creating these free weekly tutorials. On average, each tutorial takes me 15-20 hours to put together. I love offering these guides to you and I take pride in the content I create. Therefore, I will not approve comments that include large code blocks/terminal output as it destroys the formatting of the page. Kindly be respectful of this space.
  4. Be patient. I receive 200+ comments and emails per day. Due to spam, and my desire to personally answer as many questions as I can, I hand moderate all new comments (typically once per week). I try to answer as many questions as I can, but I'm only one person. Please don't be offended if I cannot get to your question
  5. Do you need priority support? Consider purchasing one of my books and courses. I place customer questions and emails in a separate, special priority queue and answer them first. If you are a customer of mine you will receive a guaranteed response from me. If there's any time left over, I focus on the community at large and attempt to answer as many of those questions as I possibly can.

Thank you for keeping these guidelines in mind before submitting your comment.

Leave a Reply