Overview

This guide will help you install OpenCV for Python using python-pip package. You can use any Python distribution like Anaconda etc.

This is for Python users, instructions for C++ users are described in a different journal.

Introduction

It is 2025 and Apple MacBook Pro machines have moved on to Apple M2 CPUs and it’s not easy to keep up with the hardware (cost-wise). We are using an Apple Mac Pro 16″ from 2019 running iOS Sonoma 14.4 (it’s a few years old but good enough for what is needed for these experiments)…

Table of Contents

    Note that once we have our environment setup by following instructions below, we will be using two key commands from Terminal, to enter and exit the Virtual Environment where we will be executing Python commands and Scripts to process our OpenCV functions…

    These are; workoncvcourse and deactivate.

    user@Users-MacBook-Pro ~ % workoncvcourse

    This switches us into the Virtual Environment

    and

    user@Users-MacBook-Pro ~ % deactivate

    This switches us out of the Virtual Environment – back to normal Terminal Commands mode..

    About this article

    This article includes a step by step guide to show how to install OPCV, Python and dependencies on MacOS and assumes the user-name ‘user’.

    However….It seems that the latest version of MacOS not only uses the theme of (user) profiles but it also defaults to user-zsh The problem with this is that after creating a Virtual Environment where we will be working on python Scripts, OpenCV libraries and commands and more significantly we want to create an ALIAS, which we would use to call up the virtual environment after starting up Terminal application.

    The ‘profiles’ theme actually stops us from doing this. Because, when we start up Terminal, it presumes we’re user zsh and ignores the bash-script for ‘user’ where our ALIAS is stored.

    For this reason, unless we switch to Profiles and create a profile before following instructions below – to make these effective for the profile(user-name) in question, we may be better off ignoring the ALIAS part and use the following command after starting up Terminal;

    # Assume we have logged in as 'user' and fired up Terminal
    # we should see the following command prompt..
    user@Users-MacBook-Pro ~ %
    
    # we then issue the following command - to fire up Virtual Environment
    user@Users-MacBook-Pro ~ % source /Users/user/opencv-course/bin/activate
    # this will then show that we're in the VirtEnv with..
    (opencv-course) user@Users-MacBook-Pro ~ % 
    #
    # An example of what we can do from there
    (opencv-course) user@Users-MacBook-Pro ~ % python sampleCode.py
    (opencv-course) user@Users-MacBook-Pro ~ % 
    # as can be seen, this command was executed without errors, which
    # in this case was to generate a grayscale copy of the colour image
    # using the CV2 library (as in the sampleCodepy script file (see below)

    This is unfortunate but only due to the way latest versions of MacOS work. As shown below, we are running Sonoma 14.4.1

    Step 1: Create a Virtual Environment

    Assuming you have python installed on your system, we will use Virtual Environments to install Python libraries. It is generally a good practice in order to separate your project environment and global environment.

    In [ ]:

    # Current Working Directory = Print Working Directory
    user@Users-MacBook-Pro ~ % cwd=$(pwd)

    creating the virtual environment


    # create virtual environment

    user@Users-MacBook-Pro ~ % python3 m venv opencvcourse

    python3 -m venv opencv-course

    # bash_profile is a script that is executed each time you start a new shell.

    We want to add a command in the script, where our Virtual Environment may be started by typing ‘workoncourse'<cr> in Terminal. This is known as an Alias…

    Add comment into bash_profile script file

    user@Users-MacBook-Pro ~ % echo "# Alias for OpenCV Course Virtual Environment" >> ~/.bash_profile

    Add the alias

    user@Users-MacBook-Pro ~ % echo “alias workoncvcourse=\”source $cwd/opencv-course/bin/activate\”” >> ~/.bash_profile

    All of the above was for future-use.

    Enter the Virtual Environment

    user@Users-MacBook-Pro ~ % source “$cwd”/opencv-course/bin/activate

    # Alternatively;
    user@Users-MacBook-Pro ~ % source /Users/user/opencv-course/bin/activate

    Upgrade pip and setup tools

    # Upgrade pip and setup tools

    Step 1 –
    user@Users-MacBook-Pro ~ % pip install –upgrade pip

    Step 2 –

    user@Users-MacBook-Pro ~ % pip install –upgrade pip setuptools

    (opencv-course) user@Users-MacBook-Pro ~ % pip install --upgrade pip setuptools
    Requirement already satisfied: pip in ./opencv-course/lib/python3.12/site-packages (24.0)
    Collecting pip
      Using cached pip-24.3.1-py3-none-any.whl.metadata (3.7 kB)
    Collecting setuptools
      Using cached setuptools-75.6.0-py3-none-any.whl.metadata (6.7 kB)
    Using cached pip-24.3.1-py3-none-any.whl (1.8 MB)
    Using cached setuptools-75.6.0-py3-none-any.whl (1.2 MB)
    Installing collected packages: setuptools, pip
      Attempting uninstall: pip
        Found existing installation: pip 24.0
        Uninstalling pip-24.0:
          Successfully uninstalled pip-24.0
    Successfully installed pip-24.3.1 setuptools-75.6.0

    Install Python Libraries

    # now install python libraries within this virtual environment
    pip install wheel numpy scipy matplotlib scikitimage scikitlearn ipython

    (opencv-course) user@Users-MacBook-Pro ~ % pip install wheel numpy scipy matplotlib scikit-image scikit-learn ipython

    View resulting process

    Collecting wheel
    Using cached wheel-0.45.0-py3-none-any.whl.metadata (2.3 kB)
    Collecting numpy
    Using cached numpy-2.1.3-cp312-cp312-macosx_14_0_x86_64.whl.metadata (62 kB)
    Collecting scipy
    Using cached scipy-1.14.1-cp312-cp312-macosx_14_0_x86_64.whl.metadata (60 kB)
    Collecting matplotlib
    Using cached matplotlib-3.9.2-cp312-cp312-macosx_10_12_x86_64.whl.metadata (11 kB)
    Collecting scikit-image
    Using cached scikit_image-0.24.0-cp312-cp312-macosx_10_9_x86_64.whl.metadata (14 kB)
    Collecting scikit-learn
    Using cached scikit_learn-1.5.2-cp312-cp312-macosx_10_9_x86_64.whl.metadata (13 kB)
    Collecting ipython
    Using cached ipython-8.29.0-py3-none-any.whl.metadata (5.0 kB)
    Collecting contourpy>=1.0.1 (from matplotlib)
    Using cached contourpy-1.3.1-cp312-cp312-macosx_10_13_x86_64.whl.metadata (5.4 kB)
    Collecting cycler>=0.10 (from matplotlib)
    Using cached cycler-0.12.1-py3-none-any.whl.metadata (3.8 kB)
    Collecting fonttools>=4.22.0 (from matplotlib)
    Using cached fonttools-4.55.0-cp312-cp312-macosx_10_13_x86_64.whl.metadata (164 kB)
    Collecting kiwisolver>=1.3.1 (from matplotlib)
    Using cached kiwisolver-1.4.7-cp312-cp312-macosx_10_9_x86_64.whl.metadata (6.3 kB)
    Collecting packaging>=20.0 (from matplotlib)
    Using cached packaging-24.2-py3-none-any.whl.metadata (3.2 kB)
    Collecting pillow>=8 (from matplotlib)
    Using cached pillow-11.0.0-cp312-cp312-macosx_10_13_x86_64.whl.metadata (9.1 kB)
    Collecting pyparsing>=2.3.1 (from matplotlib)
    Using cached pyparsing-3.2.0-py3-none-any.whl.metadata (5.0 kB)
    Collecting python-dateutil>=2.7 (from matplotlib)
    Using cached python_dateutil-2.9.0.post0-py2.py3-none-any.whl.metadata (8.4 kB)
    Collecting networkx>=2.8 (from scikit-image)
    Using cached networkx-3.4.2-py3-none-any.whl.metadata (6.3 kB)
    Collecting imageio>=2.33 (from scikit-image)
    Using cached imageio-2.36.0-py3-none-any.whl.metadata (5.2 kB)
    Collecting tifffile>=2022.8.12 (from scikit-image)
    Using cached tifffile-2024.9.20-py3-none-any.whl.metadata (32 kB)
    Collecting lazy-loader>=0.4 (from scikit-image)
    Using cached lazy_loader-0.4-py3-none-any.whl.metadata (7.6 kB)
    Collecting joblib>=1.2.0 (from scikit-learn)
    Using cached joblib-1.4.2-py3-none-any.whl.metadata (5.4 kB)
    Collecting threadpoolctl>=3.1.0 (from scikit-learn)
    Using cached threadpoolctl-3.5.0-py3-none-any.whl.metadata (13 kB)
    Collecting decorator (from ipython)
    Using cached decorator-5.1.1-py3-none-any.whl.metadata (4.0 kB)
    Collecting jedi>=0.16 (from ipython)
    Using cached jedi-0.19.2-py2.py3-none-any.whl.metadata (22 kB)
    Collecting matplotlib-inline (from ipython)
    Using cached matplotlib_inline-0.1.7-py3-none-any.whl.metadata (3.9 kB)
    Collecting prompt-toolkit<3.1.0,>=3.0.41 (from ipython)
    Using cached prompt_toolkit-3.0.48-py3-none-any.whl.metadata (6.4 kB)
    Collecting pygments>=2.4.0 (from ipython)
    Using cached pygments-2.18.0-py3-none-any.whl.metadata (2.5 kB)
    Collecting stack-data (from ipython)
    Using cached stack_data-0.6.3-py3-none-any.whl.metadata (18 kB)
    Collecting traitlets>=5.13.0 (from ipython)
    Using cached traitlets-5.14.3-py3-none-any.whl.metadata (10 kB)
    Collecting pexpect>4.3 (from ipython)
    Using cached pexpect-4.9.0-py2.py3-none-any.whl.metadata (2.5 kB)
    Collecting parso<0.9.0,>=0.8.4 (from jedi>=0.16->ipython)
    Using cached parso-0.8.4-py2.py3-none-any.whl.metadata (7.7 kB)
    Collecting ptyprocess>=0.5 (from pexpect>4.3->ipython)
    Using cached ptyprocess-0.7.0-py2.py3-none-any.whl.metadata (1.3 kB)
    Collecting wcwidth (from prompt-toolkit<3.1.0,>=3.0.41->ipython)
    Using cached wcwidth-0.2.13-py2.py3-none-any.whl.metadata (14 kB)
    Collecting six>=1.5 (from python-dateutil>=2.7->matplotlib)
    Using cached six-1.16.0-py2.py3-none-any.whl.metadata (1.8 kB)
    Collecting executing>=1.2.0 (from stack-data->ipython)
    Using cached executing-2.1.0-py2.py3-none-any.whl.metadata (8.9 kB)
    Collecting asttokens>=2.1.0 (from stack-data->ipython)
    Using cached asttokens-2.4.1-py2.py3-none-any.whl.metadata (5.2 kB)
    Collecting pure-eval (from stack-data->ipython)
    Using cached pure_eval-0.2.3-py3-none-any.whl.metadata (6.3 kB)
    Using cached wheel-0.45.0-py3-none-any.whl (72 kB)
    Using cached numpy-2.1.3-cp312-cp312-macosx_14_0_x86_64.whl (6.6 MB)
    Using cached scipy-1.14.1-cp312-cp312-macosx_14_0_x86_64.whl (25.6 MB)
    Using cached matplotlib-3.9.2-cp312-cp312-macosx_10_12_x86_64.whl (7.9 MB)
    Using cached scikit_image-0.24.0-cp312-cp312-macosx_10_9_x86_64.whl (14.1 MB)
    Using cached scikit_learn-1.5.2-cp312-cp312-macosx_10_9_x86_64.whl (12.1 MB)
    Using cached ipython-8.29.0-py3-none-any.whl (819 kB)
    Using cached contourpy-1.3.1-cp312-cp312-macosx_10_13_x86_64.whl (271 kB)
    Using cached cycler-0.12.1-py3-none-any.whl (8.3 kB)
    Using cached fonttools-4.55.0-cp312-cp312-macosx_10_13_x86_64.whl (2.3 MB)
    Using cached imageio-2.36.0-py3-none-any.whl (315 kB)
    Using cached jedi-0.19.2-py2.py3-none-any.whl (1.6 MB)
    Using cached joblib-1.4.2-py3-none-any.whl (301 kB)
    Using cached kiwisolver-1.4.7-cp312-cp312-macosx_10_9_x86_64.whl (65 kB)
    Using cached lazy_loader-0.4-py3-none-any.whl (12 kB)
    Using cached networkx-3.4.2-py3-none-any.whl (1.7 MB)
    Using cached packaging-24.2-py3-none-any.whl (65 kB)
    Using cached pexpect-4.9.0-py2.py3-none-any.whl (63 kB)
    Using cached pillow-11.0.0-cp312-cp312-macosx_10_13_x86_64.whl (3.1 MB)
    Using cached prompt_toolkit-3.0.48-py3-none-any.whl (386 kB)
    Using cached pygments-2.18.0-py3-none-any.whl (1.2 MB)
    Using cached pyparsing-3.2.0-py3-none-any.whl (106 kB)
    Using cached python_dateutil-2.9.0.post0-py2.py3-none-any.whl (229 kB)
    Using cached threadpoolctl-3.5.0-py3-none-any.whl (18 kB)
    Using cached tifffile-2024.9.20-py3-none-any.whl (228 kB)
    Using cached traitlets-5.14.3-py3-none-any.whl (85 kB)
    Using cached decorator-5.1.1-py3-none-any.whl (9.1 kB)
    Using cached matplotlib_inline-0.1.7-py3-none-any.whl (9.9 kB)
    Using cached stack_data-0.6.3-py3-none-any.whl (24 kB)
    Using cached asttokens-2.4.1-py2.py3-none-any.whl (27 kB)
    Using cached executing-2.1.0-py2.py3-none-any.whl (25 kB)
    Using cached parso-0.8.4-py2.py3-none-any.whl (103 kB)
    Using cached ptyprocess-0.7.0-py2.py3-none-any.whl (13 kB)
    Using cached six-1.16.0-py2.py3-none-any.whl (11 kB)
    Using cached pure_eval-0.2.3-py3-none-any.whl (11 kB)
    Using cached wcwidth-0.2.13-py2.py3-none-any.whl (34 kB)
    Installing collected packages: wcwidth, pure-eval, ptyprocess, wheel, traitlets, threadpoolctl, six, pyparsing, pygments, prompt-toolkit, pillow, pexpect, parso, packaging, numpy, networkx, kiwisolver, joblib, fonttools, executing, decorator, cycler, tifffile, scipy, python-dateutil, matplotlib-inline, lazy-loader, jedi, imageio, contourpy, asttokens, stack-data, scikit-learn, scikit-image, matplotlib, ipython
    Successfully installed asttokens-2.4.1 contourpy-1.3.1 cycler-0.12.1 decorator-5.1.1 executing-2.1.0 fonttools-4.55.0 imageio-2.36.0 ipython-8.29.0 jedi-0.19.2 joblib-1.4.2 kiwisolver-1.4.7 lazy-loader-0.4 matplotlib-3.9.2 matplotlib-inline-0.1.7 networkx-3.4.2 numpy-2.1.3 packaging-24.2 parso-0.8.4 pexpect-4.9.0 pillow-11.0.0 prompt-toolkit-3.0.48 ptyprocess-0.7.0 pure-eval-0.2.3 pygments-2.18.0 pyparsing-3.2.0 python-dateutil-2.9.0.post0 scikit-image-0.24.0 scikit-learn-1.5.2 scipy-1.14.1 six-1.16.0 stack-data-0.6.3 threadpoolctl-3.5.0 tifffile-2024.9.20 traitlets-5.14.3 wcwidth-0.2.13 wheel-0.45.0
    (opencv-course) user@Users-MacBook-Pro ~ %

    Exit Virtual Environment

    # quit virtual environment
    opencv-course) user@Users-MacBook-Pro ~ % deactivate

    Step 2: Install OpenCV

    Now that we have created a virtual environment (opencv-course), we will activate it (using the alias) and then install OpenCV using pip.

    In [ ]:

    source ~/.bash_profile

    # Activate the virtual environment
    workoncvcourse<cr>

    user@Users-MacBook-Pro ~ % source ~/.bash_profile
    user@Users-MacBook-Pro ~ % workoncvcourse
    (opencv-course) user@Users-MacBook-Pro ~ %


    # Install OpenCV
    pip install opencv-contrib-python
    (opencv-course) user@Users-MacBook-Pro ~ % 
    (opencv-course) user@Users-MacBook-Pro ~ % pip install opencv-contrib-python
    Collecting opencv-contrib-python
      Downloading opencv_contrib_python-4.10.0.84-cp37-abi3-macosx_12_0_x86_64.whl.metadata (20 kB)
    Requirement already satisfied: numpy>=1.21.2 in ./opencv-course/lib/python3.12/site-packages (from opencv-contrib-python) (2.1.3)
    Downloading opencv_contrib_python-4.10.0.84-cp37-abi3-macosx_12_0_x86_64.whl (66.3 MB)
       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 66.3/66.3 MB 44.5 MB/s eta 0:00:00
    Installing collected packages: opencv-contrib-python
    Successfully installed opencv-contrib-python-4.10.0.84
    (opencv-course) user@Users-MacBook-Pro ~ % 

    Step 3: Check Installation

    We are now at the final step of the installation. All that’s left to do is to verify if the installation worked.

    # First, activate the environment.
    user@Users-MacBook-Pro ~ % workoncvcourse<cr>

    (opencv-course) user@Users-MacBook-Pro ~ % 
    
    
    


    # open ipython (run this command on terminal)
    ipython

    (opencv-course) user@Users-MacBook-Pro ~ % ipython<cr>
    Python 3.12.3 (v3.12.3:f6650f9ad7, Apr 9 2024, 08:18:48) [Clang 13.0.0 (clang-1300.0.29.30)]
    Type 'copyright', 'credits' or 'license' for more information
    IPython 8.29.0 -- An enhanced Interactive Python. Type '?' for help.

    #
    # import cv2 and print the version (run following commands in ipython)
    import cv2
    print(cv2.__version__)

    # If OpenCV is installed correctly, the above command should output OpenCV version

    # The following is actual-input and output..

    In [1]: import cv2
    print(cv2.__version__)

    In [2]: print(cv2.__version__)
    4.10.0

    In [3]:


    # Press CTRL+D to exit ipython

    # Now you can exit from Python virtual environment.
    deactivate

    Final Installation checks

    If you try to run the sampleCode.py and get an error message, can’t open CV2 then you need to install the opencv-python modules within the Environment (the source of this very useful piece of information is https://sebhastian.com/modulenotfounderror-no-module-named-cv2/

    And specifically, here’s the instructions for various OS…

    Here’s a list of common install commands in popular Python environments to install the opencv-python package:
    
    # if you don't have pip in your PATH:
    python -m pip install opencv-python
    
    python3 -m pip install opencv-python
    
    # Windows
    py -m pip install opencv-python
    
    # Anaconda
    conda install opencv-python
    
    # Jupyter Notebook
    !pip install opencv-python
    

    # To check python installation inside the VirtEnv...
    (opencv-course) user@Users-MacBook-Pro opencv-course % 
    which -a python <cr>
    
    # we see that it is at the following location
    /Users/user/opencv-course/bin/python
    
    # Let's install opencv-python for our VirtEnv....
    (opencv-course) user@Users-MacBook-Pro opencv-course % python -m pip install opencv-python<cr>
    
    Collecting opencv-python
      Downloading opencv_python-4.10.0.84-cp37-abi3-macosx_12_0_x86_64.whl (56.5 MB)
         |████████████████████████████████| 56.5 MB 54.7 MB/s 
    Collecting numpy>=1.19.3
      Downloading numpy-2.0.2-cp39-cp39-macosx_14_0_x86_64.whl (6.9 MB)
         |████████████████████████████████| 6.9 MB 5.3 MB/s 
    Installing collected packages: numpy, opencv-python
    Successfully installed numpy-2.0.2 opencv-python-4.10.0.84
    
    # DONE!! Now we can run our OpenCV Python Script...
      
    (opencv-course) user@Users-MacBook-Pro opencv-course % python sampleCode.py<cr>
    (opencv-course) user@Users-MacBook-Pro opencv-course %

    Installation is complete. Now test sample code

    Test OpenCV Installation using Sample Code

    After installation of OpenCV. It’s time to test the installation using a sample code.

    In this code, we will read a colour image of a boy and save its grayscale version. Below are the input and the expected output images.

    sample image for OpenCV
    sample image for OpenCV (input file)
    Grayscale image generated by ‘python sampleCode.py‘ command, output file..

    Step 1: Download the sample code and image

    Download the zip file containing the Python script, and the input image from here.. Next, extract the zip file into a folder (Finder:untitled/Users/user/opencv-course/–unzip-here—)

    Step 2: Run the Python Script

    Make sure you are in the extracted folder on the terminal. Then, use the following command:

    It will not be evident that the following code has done anything, except that no errors are thrown.

    Lines beneath it show the actual Python commands that are being executed.

    Be sure that you have activated the virtual environment, before continuing. You can tell if you are in the virtual environment by the command prompt. I.e.

    1 –

    (opencv-course) user@Users-MacBook-Pro ~ % [you are in the virtual environment] – skip step 2 below…

    2 –

    user@Users-MacBook-Pro ~ % [ you are not in the virtual environment]

    To enter VE, type the following (bold text)

    user@Users-MacBook-Pro ~ % workoncvcourse<cr>

    In [ ]:
    python sampleCode.py

    # Here's the code
    In [2]: import cv2
    In [3]: image = cv2.imread("boy.jpg", 0)
    In [4]: cv2.imwrite("boyGray.jpg",image)
    Out[4]: True

    The code execution will generate a new file in the folder– boyGray.jpg. You can open the file and make sure it matches the expected output.

    To exit the Virtual environment, type (bold text);

    (opencv-course) user@Users-MacBook-Pro ~ % deactivate<cr>

    user@Users-MacBook-Pro ~ %

    Conclusions

    We have shown how to create a Virtual Environment called opencv-course for the user in our /User/user/ folder, which we use for OpenCV development and experiments

    We have shown how to create an Alias and inject it into our bash_profile so that we can enter the shortcut workoncourse from Terminal. This should take us directly to our Virtual Environment.

    We have installed all the tools including Python and dependencies so as to be able to run OpenCV Scripts as well as execute interactive Python commands using iPython.

    Enjoy!

    Leave a Reply