├── .github └── workflows │ └── pep8-check.yml ├── .gitignore ├── LICENSE ├── README.md ├── TESTING.md ├── abs_difference.py ├── bilateral_filter.py ├── butterworth_high_pass_filter.py ├── butterworth_low_pass_filter.py ├── camera_stream.py ├── capture_camera.py ├── capture_video.py ├── checkbuildinfo.py ├── clahe_equalization.py ├── colour_object_tracking.py ├── colour_query.py ├── contrast_stretching.py ├── correlation_template_matching.py ├── dct_low_pass_filter.py ├── exponential.py ├── fourier.py ├── gamma.py ├── high_pass_filter.py ├── histogram.py ├── histogram_equalize.py ├── hsv_viewer.py ├── jpeg_compression_noise.py ├── logarithmic.py ├── low_pass_filter.py ├── mean_filter.py ├── median_filter.py ├── nlm_filter.py ├── rgb_viewer.py ├── save_image.py ├── save_video.py ├── skeleton.py ├── smooth_image.py ├── test_all.sh ├── version.py └── ycrcb_viewer.py /.github/workflows/pep8-check.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a single version of Python 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions 3 | 4 | name: Python - PEP8 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | branches: [ master ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Set up Python 3.8 20 | uses: actions/setup-python@v2 21 | with: 22 | python-version: 3.8 23 | - name: Install dependencies 24 | run: | 25 | python -m pip install --upgrade pip 26 | pip install flake8 pytest 27 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi 28 | - name: Lint with flake8 29 | run: | 30 | # check for all PEP8 compliance issues 31 | flake8 . 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python Image Processing OpenCV Teaching Examples 2 | 3 | OpenCV Python image processing examples used for teaching within the undergraduate Computer Science programme 4 | at [Durham University](http://www.durham.ac.uk) (UK) by [Prof. Toby Breckon](https://breckon.org/toby/). 5 | 6 | ![Python - PEP8](https://github.com/tobybreckon/python-examples-ip/workflows/Python%20-%20PEP8/badge.svg) 7 | 8 | All tested with [OpenCV](http://www.opencv.org) 3.x / 4.x and Python 3.x. 9 | 10 | ``` 11 | # Example : <................................> processing from a video file 12 | # specified on the command line (e.g. python FILE.py video_file) or from an 13 | # attached web camera 14 | ``` 15 | 16 | More generally most of the examples accessing camera or video can be used as follows: 17 | 18 | ``` 19 | python3 ./skeleton.py -h 20 | usage: skeleton.py [-h] [-c CAMERA_TO_USE] [-r RESCALE] [video_file] 21 | 22 | Perform ./skeleton.py example operation on incoming camera/video image 23 | 24 | positional arguments: 25 | video_file specify optional video file 26 | 27 | optional arguments: 28 | -h, --help show this help message and exit 29 | -c CAMERA_TO_USE, --camera_to_use CAMERA_TO_USE 30 | specify camera to use 31 | -r RESCALE, --rescale RESCALE 32 | rescale image by this factor 33 | ``` 34 | 35 | Most run with a webcam connected or from a command line supplied video file of a format OpenCV supports on your system (supplied as a command line argument as per above). 36 | 37 | Demo source code is provided _"as is"_ to aid learning and understanding of topics on the course and beyond. 38 | 39 | --- 40 | 41 | ### Background: 42 | 43 | Directly adapted from the [C++](https://github.com/tobybreckon/cpp-examples-ipcv.git) and earlier [C](https://github.com/tobybreckon/cpp-examples-ipcv.git) language teaching examples used to generate the video examples within the ebook version of: 44 | 45 | [Dictionary of Computer Vision and Image Processing](http://dx.doi.org/10.1002/9781119286462) (R.B. Fisher, T.P. Breckon, K. Dawson-Howe, A. Fitzgibbon, C. Robertson, E. Trucco, C.K.I. Williams), Wiley, 2014. 46 | [[Google Books](http://books.google.co.uk/books?id=TaEQAgAAQBAJ&lpg=PP1&dq=isbn%3A1118706811&pg=PP1v=onepage&q&f=false)] [[doi](http://dx.doi.org/10.1002/9781119286462)] 47 | 48 | Notably, the [C++](https://github.com/tobybreckon/cpp-examples-ipcv.git) examples may contain further speed optimizations. 49 | 50 | --- 51 | ### How to download and run: 52 | 53 | Download each file as needed or to download the entire repository and run each try: 54 | 55 | ``` 56 | git clone https://github.com/tobybreckon/python-examples-ip.git 57 | cd python-examples-ip 58 | python3 ./.py [optional video file] 59 | ``` 60 | 61 | An extremely simple example to check if OpenCV and the other python libraries commonly needed by these examples are present/working on your system and which version of them is in use, is the ``version.py`` example: 62 | 63 | ``` 64 | python3 ./version.py 65 | ``` 66 | 67 | which should then output something like this (but with the _"x"_ elements completed 68 | specific to your system install): 69 | 70 | ``` 71 | We are using OpenCV: x.x.x 72 | .. do we have the Open CV Contrib Modules: xxxx 73 | We are using numpy: x.x.x 74 | We are using matplotlib: x.x.x 75 | .. and this is in Python: x.x.x (default, xxxxx) [xxx] 76 | ``` 77 | 78 | More generally an extended set of [OpenCV functionality tests](TESTING.md) is available (used to check OpenCV itself is working) and also a simple bash shell script (``test_all.sh``) to run through all the examples for semi-automated testing. 79 | 80 | --- 81 | 82 | ### Re-usable Exemplar Components (Python Classes): 83 | 84 | This codebase contains the following re-usable exemplar elements: 85 | 86 | - ```camera_stream.py``` - a re-usable threaded camera class, that is call compatible with the existing OpenCV VideoCapture class, designed to always deliver the latest frame from a single camera without buffering delays (used by all examples if available). 87 | 88 | The master copy of the above is available from the the [OpenCV Python Computer Vision Examples used for Teaching](https://github.com/tobybreckon/python-examples-cv) repository. 89 | 90 | --- 91 | 92 | ### Reference: 93 | 94 | All techniques are fully explained in corresponding section of: 95 | 96 | _Fundamentals of Digital Image Processing: A Practical Approach with Examples in Matlab_, 97 | Chris J. Solomon and Toby P. Breckon, Wiley-Blackwell, 2010 98 | ISBN: 0470844736, DOI:10.1002/9780470689776, http://www.fundipbook.com 99 | 100 | (which also has Matlab code examples of many of the same techniques here - [https://github.com/tobybreckon/solomon-breckon-book.git]( https://github.com/tobybreckon/solomon-breckon-book.git)) 101 | 102 | ``` 103 | @Book{solomonbreckon10fundamentals, 104 | author = {Solomon, C.J. and Breckon, T.P.}, 105 | title = {Fundamentals of Digital Image Processing: A Practical Approach with Examples in Matlab}, 106 | publisher = {Wiley-Blackwell}, 107 | year = {2010}, 108 | isbn = {0470844736}, 109 | doi = {10.1002/9780470689776}, 110 | url = {http://www.fundipbook.com} 111 | } 112 | ``` 113 | 114 | --- 115 | 116 | If you find any bugs raise an issue (or much better still submit a git pull request with a fix) - toby.breckon@durham.ac.uk 117 | 118 | _"may the source be with you"_ - anon. 119 | -------------------------------------------------------------------------------- /TESTING.md: -------------------------------------------------------------------------------- 1 | # Verification Testing for OpenCV Installation 2 | 3 | As OpenCV is a complex beast, to ensure the full installation of OpenCV is working correctly we perform the following tests. 4 | 5 | All tested with [OpenCV](http://www.opencv.org) 3.x / 4.x and Python 3.x. 6 | 7 | _Assumes that git and wget tools are available on the command line or that similar tools are available to access git / download files._ 8 | 9 | (_On-site at Durham University_: For testing on MS Windows, download and unzip example files from source URL as specified - [here](https://github.com/tobybreckon/python-examples-ip.git) - onto the user space J:/ drive. On Linux run the associated ``opencv ... .init`` shell script before testing.). 10 | 11 | --- 12 | 13 | ## Test #1 - check versions: 14 | 15 | (for testing on MS Windows at Durham (DUDE system), open all ```.py``` scripts from J:/ in IDLE and run module from there) 16 | 17 | ``` 18 | git clone https://github.com/tobybreckon/python-examples-ip.git 19 | cd python-examples-ip 20 | python3 ./version.py 21 | ``` 22 | ### Result #1: 23 | 24 | - Text output to console such that: 25 | 26 | ``` 27 | We are using OpenCV: CCC 28 | .. do we have the OpenCV Contrib Modules: True 29 | .. do we have the OpenCV Non-free algorithms: True 30 | .. do we have the Intel Performance Primitives (IPP): 31 | .. version: (in use: True) 32 | We are using numpy: 33 | We are using matplotlib: 34 | .. and this is in Python: PPP ??? (64 bit) 35 | 36 | Check Video I/O (OS identifier: MMM) 37 | ... available camera backends: LLL 38 | ... available stream backends: LLL 39 | ... available video writer backends: LLL 40 | 41 | Available Cuda Information: 42 | ... ['NVIDIA CUDA: YES (ver NNN, RRR)', 'NVIDIA GPU arch: ???', 'NVIDIA PTX archs: ZZZ'] 43 | 44 | GGG 45 | 46 | DNN module CUDA backend/target availability : 47 | ... DNN_TARGET_CUDA: True 48 | ... DNN_TARGET_CUDA_FP16: True 49 | ... DNN_TARGET_CPU: True 50 | ... DNN_TARGET_OPENCL: True 51 | ... DNN_TARGET_OPENCL_FP16: True 52 | 53 | OpenCL available (within OpenCV) ? : True 54 | 55 | Available CPU Optimizations (*: build enabled; ?: not CPU supported): 56 | ... ??? 57 | 58 | ``` 59 | - such that CCC >= 4.3.x (or higher), PPP > 3.x, MMM is sensible for the OS in use, each of the LLL list are sensible (may not all be identical) and ideally include FFMPEG + GSTREAMER in addition to V4L/V4L (for MMM = linux*), QT (for MMM = darwin) or DSHOW / MSMF (for MMM = win*), NNN > 10.x, ZZZ includes ``cuDNN: Yes``, GGG is sensible if a CUDA compatible GPU is present + configured and ??? = (doesn't matter). In addition, for maximum performance RRR ideally includes ``CUFFT CUBLAS FAST_MATH``. 60 | 61 | [ N.B. to build with Non-free algorithms set OPENCV_ENABLE_NONFREE=TRUE in CMake ] 62 | 63 | --- 64 | 65 | ## Test #1a - check we have all the correct functionality: 66 | 67 | Only to be used if building OpenCV from source (any platform) or using a pre-built version from a 3rd party repository (on Linux / Mac OS). 68 | 69 | ``` 70 | .. (as per test 1 for steps 1 + 2) 71 | python3 ./checkbuildinfo.py 72 | ``` 73 | ### Results #1a 74 | 75 | - The resulting build element information should ideally contain the following as a subset of the configuration (where _present_ indicates a reference to a system file or a version number that tells us it is present on the system / in the build): 76 | 77 | | build element | Linux | MS Windows | 78 | |------------------------------------ | ----- | --------| 79 | | Platform: ... Configuration: |Release|Release| 80 | | Built as dynamic libs: | YES | YES | 81 | | OpenCV modules: | contains: core flann ... imgproc ... ml ... imgcodecs ... videoio .. xfeatures2d ... dnn ... dnn_objdetect ... ximgproc ... optflow ... stitching ... **cuda** | <-- same as Linux| 82 | | Non-free algorithms: | YES | YES | 83 | | QT: | NO | NO | 84 | | GTK+ 2.x: | YES | NO | 85 | | ZLib: | present | present | 86 | | JPEG: | present | present | 87 | | WEBP: | present | present | 88 | | PNG: | present | present | 89 | | JPEG 2000: | present | present | 90 | | OpenEXR: | present | present | 91 | | PNG: | present | present | 92 | | FFMPEG: | YES (all sub-elements)| NO | 93 | | GStreamer: | YES (all sub-elements)| NO | 94 | | V4L/V4L2: | present | NO | 95 | | XINE: | YES | NO | 96 | | gPhoto2: | YES | NO | 97 | | Parallel framework: | pthreads | ??? | 98 | | Use IPP: | present | NO | 99 | | **NVIDIA CUDA:** | YES ( >= 10.x) | NO | 100 | | **OpenCL:** | YES | YES | 101 | 102 | - elements **in bold** required for OpenCV 4.3.x and later on Linux (to enable GPU use for CNN/DNN inference via DNN module). 103 | 104 | --- 105 | 106 | ## Test #2 - check image read + window display functions: 107 | 108 | (for MS Windows download image from [here](https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg) and save as example.jpg in directory python-examples-ip-master) 109 | 110 | ``` 111 | .. (as per test 1 for steps 1 + 2) 112 | wget https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg 113 | mv JPEG_example_JPG_RIP_100.jpg example.jpg 114 | python3 ./smooth_image.py 115 | ``` 116 | 117 | ### Result #2: 118 | - image is displayed in window (a blurred version of example.jpg), 119 | pressing 'x' closes window. 120 | 121 | --- 122 | 123 | ## Test #3 - test camera access and video write function: 124 | 125 | ``` 126 | .. (as per test 1 for steps 1 + 2) 127 | <<< connect a usb web-cam (any web-cam) 128 | python3 ./save_video.py -c 0 129 | ``` 130 | 131 | ## Result #3: 132 | - possible error message such as "???... ???? Unable to open source 'input.avi'" - _ignore this_. 133 | - possible error message relating to inability to read from camera or video device (try with ``-c 1`` or greater to address different video devices) 134 | - a window appears with live video from camera, pressing 'x' closes window and ends program (saving a video file). 135 | - video file saved as _output.avi_ file can be played in [vlc](http://www.vlc.org) or similar. 136 | - Ignore _"cannot open video messages"_ from ffpmeg/xine or similar (this is it failing to open video file as alt. to camera, not write from camera). 137 | 138 | --- 139 | 140 | ## Test #4 - test video read function: 141 | 142 | (for MS Windows download video from [here](https://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_720p_surround.avi) and save as video.avi in directory python-examples-ip-master) 143 | 144 | ``` 145 | .. (as per test 1 for steps 1 + 2) 146 | wget https://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_720p_surround.avi 147 | mv big_buck_bunny_720p_surround.avi video.avi 148 | python3 ./capture_video.py 149 | ``` 150 | 151 | ### Result #4: 152 | 153 | - The video available at 154 | http://camendesign.co.uk/code/video_for_everybody/test.html is played 155 | back in a window, but with no audio. 156 | 157 | --- 158 | -------------------------------------------------------------------------------- /abs_difference.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : simple image differencing and contrast via multiplication 4 | # from a video file specified on the command line 5 | # (e.g. python FILE.py video_file) or from an attached web camera 6 | 7 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 8 | 9 | # Copyright (c) 2015 School of Engineering & Computing Science, 10 | # Copyright (c) 2019 Dept Computer Science, 11 | # Durham University, UK 12 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 13 | 14 | ##################################################################### 15 | 16 | import cv2 17 | import argparse 18 | import sys 19 | 20 | ##################################################################### 21 | 22 | keep_processing = True 23 | 24 | # parse command line arguments for camera ID or video file 25 | 26 | parser = argparse.ArgumentParser( 27 | description='Perform ' + 28 | sys.argv[0] + 29 | ' example operation on incoming camera/video image') 30 | parser.add_argument( 31 | "-c", 32 | "--camera_to_use", 33 | type=int, 34 | help="specify camera to use", 35 | default=0) 36 | parser.add_argument( 37 | "-r", 38 | "--rescale", 39 | type=float, 40 | help="rescale image by this factor", 41 | default=1.0) 42 | parser.add_argument( 43 | 'video_file', 44 | metavar='video_file', 45 | type=str, 46 | nargs='?', 47 | help='specify optional video file') 48 | args = parser.parse_args() 49 | use_greyscale = False 50 | 51 | 52 | ##################################################################### 53 | 54 | # this function is called as a call-back everytime the trackbar is moved 55 | # (here we just do nothing) 56 | 57 | def nothing(x): 58 | pass 59 | 60 | 61 | ##################################################################### 62 | 63 | # define video capture object 64 | 65 | try: 66 | # to use a non-buffered camera stream (via a separate thread) 67 | 68 | if not (args.video_file): 69 | import camera_stream 70 | cap = camera_stream.CameraVideoStream(use_tapi=False) 71 | else: 72 | cap = cv2.VideoCapture() # not needed for video files 73 | 74 | except BaseException: 75 | # if not then just use OpenCV default 76 | 77 | print("INFO: camera_stream class not found - camera input may be buffered") 78 | cap = cv2.VideoCapture() 79 | 80 | # define display window name 81 | 82 | window_name = "Live Camera Input" # window name 83 | window_name2 = "Difference Image" # window name 84 | 85 | # if command line arguments are provided try to read video_file 86 | # otherwise default to capture from attached H/W camera 87 | 88 | if (((args.video_file) and (cap.open(str(args.video_file)))) 89 | or (cap.open(args.camera_to_use))): 90 | 91 | # create windows by name (as resizable) 92 | 93 | cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) 94 | cv2.namedWindow(window_name2, cv2.WINDOW_NORMAL) 95 | 96 | # add some track bar controllers for settings 97 | 98 | contrast = 1 99 | cv2.createTrackbar("contrast", window_name2, contrast, 30, nothing) 100 | 101 | fps = 25 102 | cv2.createTrackbar("fps", window_name2, fps, 25, nothing) 103 | 104 | threshold = 0 105 | cv2.createTrackbar("threshold", window_name2, threshold, 255, nothing) 106 | 107 | # if video file or camera successfully open then read frame from video 108 | 109 | if (cap.isOpened): 110 | ret, frame = cap.read() 111 | 112 | # rescale if specified 113 | 114 | if (args.rescale != 1.0): 115 | frame = cv2.resize(frame, (0, 0), fx=args.rescale, fy=args.rescale) 116 | 117 | # make a deep copy of this (as all camera frames otherwise reside 118 | # in the same portion of allocated memory) 119 | 120 | prev_frame = frame.copy() 121 | 122 | while (keep_processing): 123 | 124 | # if video file or camera successfully open then read frame from video 125 | 126 | if (cap.isOpened): 127 | ret, frame = cap.read() 128 | 129 | # when we reach the end of the video (file) exit cleanly 130 | 131 | if (ret == 0): 132 | keep_processing = False 133 | continue 134 | 135 | # rescale if specified 136 | 137 | if (args.rescale != 1.0): 138 | frame = cv2.resize( 139 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 140 | 141 | if (use_greyscale): 142 | frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 143 | # if the previous frame we stored also has 3 channels (colour) 144 | if (len(prev_frame.shape) == 3): 145 | # convert it, otherwise absdiff() will break 146 | prev_frame = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY) 147 | 148 | # performing absolute differencing between consecutive frames 149 | 150 | diff_img = cv2.absdiff(prev_frame, frame) 151 | 152 | # retrieve the contrast setting from the track bar 153 | 154 | contrast = cv2.getTrackbarPos("contrast", window_name2) 155 | 156 | # multiple the result to increase the contrast (so we can see small 157 | # pixel changes) 158 | 159 | brightened_img = diff_img * contrast 160 | 161 | # display images 162 | 163 | cv2.imshow(window_name, frame) 164 | 165 | # threshold the image if its in grayscale and we have a valid threshold 166 | 167 | threshold = cv2.getTrackbarPos("threshold", window_name2) 168 | 169 | if (use_greyscale and (threshold > 0)): 170 | 171 | # display thresholded image if threshold > 0 172 | # thresholding : if pixel > (threshold value) set to 255 (white), 173 | # otherwise set to 0 (black) 174 | 175 | ret, thresholded_img = cv2.threshold( 176 | brightened_img, 127, 255, cv2.THRESH_BINARY) 177 | cv2.imshow(window_name2, thresholded_img) 178 | else: 179 | # otherwise just display the non-thresholded one 180 | 181 | cv2.imshow(window_name2, brightened_img) 182 | 183 | # start the event loop - essential 184 | 185 | # cv2.waitKey() is a keyboard binding function (argument is the time in 186 | # ms). It waits for specified milliseconds for any keyboard event. 187 | # If you press any key in that time, the program continues. 188 | # If 0 is passed, it waits indefinitely for a key stroke. 189 | # (bitwise and with 0xFF to extract least significant byte of 190 | # multi-byte response) 191 | 192 | fps = cv2.getTrackbarPos("fps", window_name2) 193 | # wait T ms (i.e. 1000ms / 25 fps = 40 ms) 194 | key = cv2.waitKey(int(1000 / max(1, fps))) & 0xFF 195 | 196 | # It can also be set to detect specific key strokes by recording which 197 | # key is pressed 198 | 199 | # e.g. if user presses "x" then exit 200 | 201 | if (key == ord('x')): 202 | keep_processing = False 203 | 204 | elif (key == ord('g')): 205 | 206 | # toggle grayscale usage (when they press 'g') 207 | 208 | use_greyscale = not (use_greyscale) 209 | 210 | # if the previous frame we stored also has 3 channels (colour) 211 | if (len(prev_frame.shape) != 3): 212 | # convert it to just copying the gray information to all of the 213 | # three channels (this is a hack), otherwise absdiff() will 214 | # break 215 | prev_frame = cv2.cvtColor(prev_frame, cv2.COLOR_GRAY2BGR) 216 | else: 217 | 218 | # make a deep copy of the current frame (as all camera frames 219 | # otherwise reside in the same portion of allocated memory) 220 | prev_frame = frame.copy() 221 | 222 | # close all windows 223 | 224 | cv2.destroyAllWindows() 225 | 226 | else: 227 | print("No video file specified or camera connected.") 228 | 229 | ##################################################################### 230 | -------------------------------------------------------------------------------- /bilateral_filter.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : gaussian and bi-lateral filtering on an image from an attached 4 | # web camera 5 | 6 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 7 | 8 | # Copyright (c) 2015 School of Engineering & Computing Science, 9 | # Copyright (c) 2019 Dept Computer Science, 10 | # Durham University, UK 11 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 12 | 13 | ##################################################################### 14 | 15 | import cv2 16 | import sys 17 | import argparse 18 | 19 | ##################################################################### 20 | 21 | keep_processing = True 22 | 23 | # parse command line arguments for camera ID or video file 24 | 25 | parser = argparse.ArgumentParser( 26 | description='Perform ' + 27 | sys.argv[0] + 28 | ' example operation on incoming camera/video image') 29 | parser.add_argument( 30 | "-c", 31 | "--camera_to_use", 32 | type=int, 33 | help="specify camera to use", 34 | default=0) 35 | parser.add_argument( 36 | "-r", 37 | "--rescale", 38 | type=float, 39 | help="rescale image by this factor", 40 | default=1.0) 41 | parser.add_argument( 42 | 'video_file', 43 | metavar='video_file', 44 | type=str, 45 | nargs='?', 46 | help='specify optional video file') 47 | args = parser.parse_args() 48 | 49 | 50 | ##################################################################### 51 | 52 | # this function is called as a call-back everytime the trackbar is moved 53 | # (here we just do nothing) 54 | 55 | def nothing(x): 56 | pass 57 | 58 | 59 | ##################################################################### 60 | 61 | # define video capture object 62 | 63 | try: 64 | # to use a non-buffered camera stream (via a separate thread) 65 | 66 | if not (args.video_file): 67 | import camera_stream 68 | cap = camera_stream.CameraVideoStream(use_tapi=False) 69 | else: 70 | cap = cv2.VideoCapture() # not needed for video files 71 | 72 | except BaseException: 73 | # if not then just use OpenCV default 74 | 75 | print("INFO: camera_stream class not found - camera input may be buffered") 76 | cap = cv2.VideoCapture() 77 | 78 | # define display window name 79 | 80 | window_name = "Live Camera Input" # window name 81 | window_name2 = "Gaussian Smoothing" # window name 82 | window_name3 = "Bilaterial Filtering" # window name 83 | 84 | # if command line arguments are provided try to read video_file 85 | # otherwise default to capture from attached H/W camera 86 | 87 | if (((args.video_file) and (cap.open(str(args.video_file)))) 88 | or (cap.open(args.camera_to_use))): 89 | 90 | # create window by name 91 | 92 | cv2.namedWindow(window_name, cv2.WINDOW_AUTOSIZE) 93 | cv2.namedWindow(window_name2, cv2.WINDOW_AUTOSIZE) 94 | cv2.namedWindow(window_name3, cv2.WINDOW_AUTOSIZE) 95 | 96 | # add some track bar controllers for settings Gaussian smoothing 97 | 98 | neighbourhood = 3 99 | cv2.createTrackbar( 100 | "neighbourhood, N", 101 | window_name2, 102 | neighbourhood, 103 | 40, 104 | nothing) 105 | sigma = 1 106 | cv2.createTrackbar("sigma", window_name2, sigma, 10, nothing) 107 | 108 | # add some track bar controllers for settings bilateral smoothing 109 | 110 | sigma_s = 10 111 | cv2.createTrackbar("sigma S", window_name3, sigma_s, 25, nothing) 112 | sigma_r = 10 113 | cv2.createTrackbar("sigma R", window_name3, sigma_r, 25, nothing) 114 | 115 | while (keep_processing): 116 | 117 | # if video file or camera successfully open then read frame from video 118 | 119 | if (cap.isOpened): 120 | ret, frame = cap.read() 121 | 122 | # when we reach the end of the video (file) exit cleanly 123 | 124 | if (ret == 0): 125 | keep_processing = False 126 | continue 127 | 128 | # rescale if specified 129 | 130 | if (args.rescale != 1.0): 131 | frame = cv2.resize( 132 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 133 | 134 | # get parameter from track bars - Gaussian 135 | 136 | neighbourhood = cv2.getTrackbarPos("neighbourhood, N", window_name2) 137 | sigma = cv2.getTrackbarPos("sigma", window_name2) 138 | 139 | # get parameter from track bars - bilateral 140 | 141 | sigma_s = cv2.getTrackbarPos("sigma S", window_name3) 142 | sigma_r = cv2.getTrackbarPos("sigma R", window_name3) 143 | 144 | # check neighbourhood is greater than 3 and odd 145 | 146 | neighbourhood = max(3, neighbourhood) 147 | if not (neighbourhood % 2): 148 | neighbourhood = neighbourhood + 1 149 | 150 | # perform Gaussian smoothing using NxN neighbourhood 151 | 152 | smoothed_img = cv2.GaussianBlur( 153 | frame, 154 | (neighbourhood, 155 | neighbourhood), 156 | sigma, 157 | sigma, 158 | borderType=cv2.BORDER_REPLICATE) 159 | 160 | # perform bilateral filtering using a neighbourhood calculated 161 | # automatically from sigma_s 162 | 163 | filtered_img = cv2.bilateralFilter( 164 | frame, -1, sigma_r, sigma_s, borderType=cv2.BORDER_REPLICATE) 165 | 166 | # display image 167 | 168 | cv2.imshow(window_name, frame) 169 | cv2.imshow(window_name2, smoothed_img) 170 | cv2.imshow(window_name3, filtered_img) 171 | 172 | # start the event loop - essential 173 | 174 | # cv2.waitKey() is a keyboard binding function (argument is the time in 175 | # ms). It waits for specified milliseconds for any keyboard event. 176 | # If you press any key in that time, the program continues. 177 | # If 0 is passed, it waits indefinitely for a key stroke. 178 | # (bitwise and with 0xFF to extract least significant byte of 179 | # multi-byte response) 180 | 181 | # wait 40ms (i.e. 1000ms / 25 fps = 40 ms) 182 | key = cv2.waitKey(40) & 0xFF 183 | 184 | # It can also be set to detect specific key strokes by recording which 185 | # key is pressed 186 | 187 | # e.g. if user presses "x" then exit 188 | 189 | if (key == ord('x')): 190 | keep_processing = False 191 | 192 | # close all windows 193 | 194 | cv2.destroyAllWindows() 195 | 196 | else: 197 | print("No usable camera connected.") 198 | 199 | 200 | ##################################################################### 201 | -------------------------------------------------------------------------------- /butterworth_low_pass_filter.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : perform butterworth low pass filtering in fourier space of 4 | # image frame from a video file specified on the command line 5 | # (e.g. python FILE.py video_file) or from an attached web camera 6 | 7 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 8 | 9 | # Copyright (c) 2015 School of Engineering & Computing Science, 10 | # Copyright (c) 2019 Dept Computer Science, 11 | # Durham University, UK 12 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 13 | 14 | ##################################################################### 15 | 16 | import cv2 17 | import argparse 18 | import sys 19 | import numpy as np 20 | import math 21 | 22 | ##################################################################### 23 | 24 | # ignore divide by zero errors in np.log() operations 25 | 26 | np.seterr(divide='ignore') 27 | 28 | ##################################################################### 29 | 30 | keep_processing = True 31 | 32 | # parse command line arguments for camera ID or video file 33 | 34 | parser = argparse.ArgumentParser( 35 | description='Perform ' + 36 | sys.argv[0] + 37 | ' example operation on incoming camera/video image') 38 | parser.add_argument( 39 | "-c", 40 | "--camera_to_use", 41 | type=int, 42 | help="specify camera to use", 43 | default=0) 44 | parser.add_argument( 45 | "-r", 46 | "--rescale", 47 | type=float, 48 | help="rescale image by this factor", 49 | default=1.0) 50 | parser.add_argument( 51 | 'video_file', 52 | metavar='video_file', 53 | type=str, 54 | nargs='?', 55 | help='specify optional video file') 56 | args = parser.parse_args() 57 | 58 | 59 | recompute_filter = True 60 | 61 | ##################################################################### 62 | 63 | # create a butterworth low pass filter 64 | 65 | 66 | def create_butterworth_low_pass_filter(width, height, d, n): 67 | lp_filter = np.zeros((height, width, 2), np.float32) 68 | centre = (width / 2, height / 2) 69 | 70 | # based on the forumla in lecture 8 (2015 version) 71 | # see also HIPR2 on-line 72 | 73 | for i in range(0, lp_filter.shape[1]): # image width 74 | for j in range(0, lp_filter.shape[0]): # image height 75 | radius = max( 76 | 1, 77 | math.sqrt( 78 | math.pow( 79 | (i - 80 | centre[0]), 81 | 2.0) + 82 | math.pow( 83 | (j - 84 | centre[1]), 85 | 2.0))) 86 | lp_filter[j, i] = 1 / (1 + math.pow((radius / d), (2 * n))) 87 | 88 | return lp_filter 89 | 90 | 91 | ##################################################################### 92 | 93 | # this function is called as a call-back everytime the trackbar is moved 94 | # to signal we need to reconstruct the filter 95 | 96 | def reset_butterworth_filter(_): 97 | global recompute_filter 98 | recompute_filter = True 99 | return 100 | 101 | 102 | ##################################################################### 103 | 104 | # define video capture object 105 | 106 | try: 107 | # to use a non-buffered camera stream (via a separate thread) 108 | 109 | if not (args.video_file): 110 | import camera_stream 111 | cap = camera_stream.CameraVideoStream(use_tapi=False) 112 | else: 113 | cap = cv2.VideoCapture() # not needed for video files 114 | 115 | except BaseException: 116 | # if not then just use OpenCV default 117 | 118 | print("INFO: camera_stream class not found - camera input may be buffered") 119 | cap = cv2.VideoCapture() 120 | 121 | # define display window name 122 | 123 | window_name = "Live Camera Input" # window name 124 | window_name2 = "Fourier Magnitude Spectrum" # window name 125 | window_name3 = "Filtered Image" # window name 126 | window_name4 = "Butterworth Filter" # window name 127 | 128 | # if command line arguments are provided try to read video_file 129 | # otherwise default to capture from attached H/W camera 130 | 131 | if (((args.video_file) and (cap.open(str(args.video_file)))) 132 | or (cap.open(args.camera_to_use))): 133 | 134 | # create windows by name (as resizable) 135 | 136 | cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) 137 | cv2.namedWindow(window_name2, cv2.WINDOW_NORMAL) 138 | cv2.namedWindow(window_name3, cv2.WINDOW_NORMAL) 139 | cv2.namedWindow(window_name4, cv2.WINDOW_NORMAL) 140 | 141 | # add some track bar controllers for settings 142 | 143 | radius = 5 144 | cv2.createTrackbar( 145 | "radius", 146 | window_name4, 147 | radius, 148 | 100, 149 | reset_butterworth_filter) 150 | order = 1 151 | cv2.createTrackbar( 152 | "order", 153 | window_name4, 154 | order, 155 | 10, 156 | reset_butterworth_filter) 157 | 158 | # if video file or camera successfully open then read frame from video 159 | 160 | if (cap.isOpened): 161 | ret, frame = cap.read() 162 | 163 | # rescale if specified 164 | 165 | if (args.rescale != 1.0): 166 | frame = cv2.resize(frame, (0, 0), fx=args.rescale, fy=args.rescale) 167 | 168 | # convert to grayscale 169 | 170 | gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 171 | 172 | # use this single frame to set up optimized DFT settings 173 | 174 | hieght, width = gray_frame.shape 175 | nheight = cv2.getOptimalDFTSize(hieght) 176 | nwidth = cv2.getOptimalDFTSize(width) 177 | 178 | while (keep_processing): 179 | 180 | # if video file or camera successfully open then read frame from video 181 | 182 | if (cap.isOpened): 183 | ret, frame = cap.read() 184 | 185 | # when we reach the end of the video (file) exit cleanly 186 | 187 | if (ret == 0): 188 | keep_processing = False 189 | continue 190 | 191 | # rescale if specified 192 | 193 | if (args.rescale != 1.0): 194 | frame = cv2.resize( 195 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 196 | 197 | # start a timer (to see how long processing and display takes) 198 | 199 | start_t = cv2.getTickCount() 200 | 201 | # convert to grayscale 202 | 203 | gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 204 | 205 | # Performance of DFT calculation, via the FFT, is better for array 206 | # sizes of power of two. Arrays whose size is a product of 207 | # 2's, 3's, and 5's are also processed quite efficiently. 208 | # Hence we modify the size of the array to the optimal size (by padding 209 | # zeros) before finding DFT. 210 | 211 | pad_right = nwidth - width 212 | pad_bottom = nheight - hieght 213 | nframe = cv2.copyMakeBorder( 214 | gray_frame, 215 | 0, 216 | pad_bottom, 217 | 0, 218 | pad_right, 219 | cv2.BORDER_CONSTANT, 220 | value=0) 221 | 222 | # perform the DFT and get complex output 223 | 224 | dft = cv2.dft(np.float32(nframe), flags=cv2.DFT_COMPLEX_OUTPUT) 225 | 226 | # shift it so that we the zero-frequency, F(0,0), DC component to the 227 | # center of the spectrum. 228 | 229 | dft_shifted = np.fft.fftshift(dft) 230 | 231 | # perform low pass filtering 232 | 233 | radius = cv2.getTrackbarPos("radius", window_name4) 234 | order = cv2.getTrackbarPos("order", window_name4) 235 | 236 | # butterworth is slow to construct so only do it when needed (i.e. 237 | # trackbar changes) 238 | 239 | if (recompute_filter): 240 | lp_filter = create_butterworth_low_pass_filter( 241 | nwidth, nheight, radius, order) 242 | recompute_filter = False 243 | 244 | dft_filtered = cv2.mulSpectrums(dft_shifted, lp_filter, flags=0) 245 | 246 | # shift it back to original quaderant ordering 247 | 248 | dft = np.fft.fftshift(dft_filtered) 249 | 250 | # recover the original image via the inverse DFT 251 | 252 | filtered_img = cv2.dft(dft, flags=cv2.DFT_INVERSE) 253 | 254 | # normalized the filtered image into 0 -> 255 (8-bit grayscale) so we 255 | # can see the output 256 | 257 | min_val, max_val, min_loc, max_loc = \ 258 | cv2.minMaxLoc(filtered_img[:, :, 0]) 259 | filtered_img_normalized = filtered_img[:, :, 0] * ( 260 | 1.0 / (max_val - min_val)) + ((-min_val) / (max_val - min_val)) 261 | filtered_img_normalized = np.uint8(filtered_img_normalized * 255) 262 | 263 | # calculate the magnitude spectrum and log transform + scale it for 264 | # visualization 265 | 266 | magnitude_spectrum = np.log(cv2.magnitude( 267 | dft_filtered[:, :, 0], dft_filtered[:, :, 1])) 268 | 269 | # create a 8-bit image to put the magnitude spectrum into 270 | 271 | magnitude_spectrum_normalized = np.zeros( 272 | (nheight, nwidth, 1), np.uint8) 273 | 274 | # normalized the magnitude spectrum into 0 -> 255 (8-bit grayscale) so 275 | # we can see the output 276 | 277 | cv2.normalize( 278 | np.uint8(magnitude_spectrum), 279 | magnitude_spectrum_normalized, 280 | alpha=0, 281 | beta=255, 282 | norm_type=cv2.NORM_MINMAX) 283 | 284 | # display images 285 | 286 | cv2.imshow(window_name, gray_frame) 287 | cv2.imshow(window_name2, magnitude_spectrum_normalized) 288 | cv2.imshow(window_name3, filtered_img_normalized) 289 | cv2.imshow(window_name4, lp_filter[:, :, 0] * 255) 290 | 291 | # stop timer and convert to ms. (to see how long processing and display 292 | # takes) 293 | 294 | stop_t = ((cv2.getTickCount() - start_t) / 295 | cv2.getTickFrequency()) * 1000 296 | 297 | # start the event loop - essential 298 | 299 | # cv2.waitKey() is a keyboard binding function (argument is the time in 300 | # ms). It waits for specified milliseconds for any keyboard event. 301 | # If you press any key in that time, the program continues. 302 | # If 0 is passed, it waits indefinitely for a key stroke. 303 | # (bitwise and with 0xFF to extract least significant byte of 304 | # multi-byte response) 305 | 306 | # here we use a wait time in ms. that takes account of processing time 307 | # already used in the loop 308 | 309 | # wait 40ms (i.e. 1000ms / 25 fps = 40 ms) 310 | key = cv2.waitKey(max(2, 40 - int(math.ceil(stop_t)))) & 0xFF 311 | 312 | # It can also be set to detect specific key strokes by recording which 313 | # key is pressed 314 | 315 | # e.g. if user presses "x" then exit 316 | 317 | if (key == ord('x')): 318 | keep_processing = False 319 | 320 | # close all windows 321 | 322 | cv2.destroyAllWindows() 323 | 324 | else: 325 | print("No video file specified or camera connected.") 326 | 327 | ##################################################################### 328 | -------------------------------------------------------------------------------- /capture_camera.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : capture an image from an attached camera 4 | 5 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 6 | 7 | # Copyright (c) 2015 School of Engineering & Computing Science, 8 | # Copyright (c) 2019 Dept Computer Science, 9 | # Durham University, UK 10 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 11 | 12 | ##################################################################### 13 | 14 | import cv2 15 | import argparse 16 | import sys 17 | 18 | ##################################################################### 19 | 20 | # parse command line arguments for camera ID or video file 21 | 22 | parser = argparse.ArgumentParser( 23 | description='Perform ' + 24 | sys.argv[0] + 25 | ' example operation on incoming camera/video image') 26 | parser.add_argument( 27 | "-c", 28 | "--camera_to_use", 29 | type=int, 30 | help="specify camera to use", 31 | default=0) 32 | parser.add_argument( 33 | "-r", 34 | "--rescale", 35 | type=float, 36 | help="rescale image by this factor", 37 | default=1.0) 38 | args = parser.parse_args() 39 | 40 | ##################################################################### 41 | 42 | # define video capture object 43 | 44 | try: 45 | # to use a non-buffered camera stream (via a separate thread) 46 | 47 | import camera_stream 48 | cap = camera_stream.CameraVideoStream(use_tapi=False) 49 | 50 | except BaseException: 51 | # if not then just use OpenCV default 52 | 53 | print("INFO: camera_stream class not found - camera input may be buffered") 54 | cap = cv2.VideoCapture() 55 | 56 | # define display window name 57 | 58 | window_name = "Live Camera Input" # window name 59 | 60 | # open camera device (and check it worked) 61 | 62 | if not (cap.open(args.camera_to_use)): 63 | print("Cannot open camera - check connection and operation as suggested.") 64 | sys.exit 65 | 66 | # read an image from the camera 67 | 68 | ret, frame = cap.read() 69 | 70 | # to avoid the black/blank first frame from many cameras 71 | # with some (not all) cameras you need to read the first frame twice 72 | # (first frame only) 73 | 74 | ret, frame = cap.read() 75 | 76 | # check it has loaded 77 | 78 | if frame is not None: 79 | 80 | # create window by name (as resizable) 81 | 82 | cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) 83 | 84 | # display image 85 | 86 | cv2.imshow(window_name, frame) 87 | 88 | # start the event loop - essential 89 | # wait indefinitely for any key press 90 | 91 | cv2.waitKey(0) 92 | 93 | else: 94 | print("No image successfully loaded from camera.") 95 | 96 | # close all windows 97 | 98 | cv2.destroyAllWindows() 99 | 100 | ##################################################################### 101 | -------------------------------------------------------------------------------- /capture_video.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : generic interface example for video processing from a video file 4 | # specified by filename or from an attached web camera 5 | 6 | # example test videos avilable from: 7 | # http://camendesign.co.uk/code/video_for_everybody/test.html 8 | 9 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 10 | 11 | # Copyright (c) 2015 School of Engineering & Computing Science, 12 | # Copyright (c) 2019 Dept Computer Science, 13 | # Durham University, UK 14 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 15 | 16 | ##################################################################### 17 | 18 | import cv2 19 | import argparse 20 | import sys 21 | 22 | ##################################################################### 23 | 24 | keep_processing = True 25 | 26 | # parse command line arguments for camera ID or video file 27 | 28 | parser = argparse.ArgumentParser( 29 | description='Perform ' + 30 | sys.argv[0] + 31 | ' example operation on incoming camera/video image') 32 | parser.add_argument( 33 | "-c", 34 | "--camera_to_use", 35 | type=int, 36 | help="specify camera to use", 37 | default=0) 38 | parser.add_argument( 39 | "-r", 40 | "--rescale", 41 | type=float, 42 | help="rescale image by this factor", 43 | default=1.0) 44 | args = parser.parse_args() 45 | 46 | ##################################################################### 47 | 48 | # define video capture object 49 | 50 | cap = cv2.VideoCapture() 51 | 52 | # define display window name 53 | 54 | window_name = "Live Camera Input" # window name 55 | 56 | # if file is present try to read video_file 57 | # otherwise default to capture from attached H/W camera 58 | 59 | if ((cap.open("video.avi")) or (cap.open(args.camera_to_use))): 60 | 61 | # create window by name (as resizable) 62 | 63 | cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) 64 | 65 | while (keep_processing): 66 | 67 | # if video file or camera successfully open then read frame from video 68 | 69 | if (cap.isOpened): 70 | ret, frame = cap.read() 71 | 72 | # when we reach the end of the video (file) exit cleanly 73 | 74 | if (ret == 0): 75 | keep_processing = False 76 | continue 77 | 78 | # rescale if specified 79 | 80 | if (args.rescale != 1.0): 81 | frame = cv2.resize( 82 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 83 | 84 | # *** do any processing here **** 85 | 86 | # display image 87 | 88 | cv2.imshow(window_name, frame) 89 | 90 | # start the event loop - essential 91 | 92 | # cv2.waitKey() is a keyboard binding function (argument is the time in 93 | # ms). It waits for specified milliseconds for any keyboard event. 94 | # If you press any key in that time, the program continues. 95 | # If 0 is passed, it waits indefinitely for a key stroke. 96 | # (bitwise and with 0xFF to extract least significant byte of 97 | # multi-byte response) 98 | 99 | # wait 40ms (i.e. 1000ms / 25 fps = 40 ms) 100 | key = cv2.waitKey(40) & 0xFF 101 | 102 | # It can also be set to detect specific key strokes by recording which 103 | # key is pressed 104 | 105 | # e.g. if user presses "x" then exit 106 | 107 | if (key == ord('x')): 108 | keep_processing = False 109 | 110 | # close all windows 111 | 112 | cv2.destroyAllWindows() 113 | 114 | else: 115 | print("No video file specified or camera connected.") 116 | 117 | 118 | ##################################################################### 119 | -------------------------------------------------------------------------------- /checkbuildinfo.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : display the build options for OpenCV 4 | 5 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 6 | 7 | # Copyright (c) 2017 Toby Breckon 8 | # Durham University, UK 9 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 10 | 11 | ##################################################################### 12 | 13 | import cv2 14 | 15 | print("You are using OpenCV: " + cv2.__version__) 16 | print() 17 | print("OpenCV is built using the following options:") 18 | print(cv2.getBuildInformation()) 19 | 20 | ##################################################################### 21 | -------------------------------------------------------------------------------- /clahe_equalization.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : perform contrast limited histogram equalization (CLAHE) 4 | # from a video filespecified on the command line (e.g. python FILE.py 5 | # video_file) or from an attached web camera 6 | 7 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 8 | 9 | # Copyright (c) 2015 School of Engineering & Computing Science, 10 | # Copyright (c) 2019 Dept Computer Science, 11 | # Durham University, UK 12 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 13 | 14 | ##################################################################### 15 | 16 | import cv2 17 | import argparse 18 | import numpy as np 19 | import sys 20 | 21 | ##################################################################### 22 | 23 | keep_processing = True 24 | 25 | # parse command line arguments for camera ID or video file 26 | 27 | parser = argparse.ArgumentParser( 28 | description='Perform ' + 29 | sys.argv[0] + 30 | ' example operation on incoming camera/video image') 31 | parser.add_argument( 32 | "-c", 33 | "--camera_to_use", 34 | type=int, 35 | help="specify camera to use", 36 | default=0) 37 | parser.add_argument( 38 | "-r", 39 | "--rescale", 40 | type=float, 41 | help="rescale image by this factor", 42 | default=1.0) 43 | parser.add_argument( 44 | 'video_file', 45 | metavar='video_file', 46 | type=str, 47 | nargs='?', 48 | help='specify optional video file') 49 | args = parser.parse_args() 50 | 51 | ##################################################################### 52 | 53 | # basic grayscale histogram drawing in raw OpenCV using lines 54 | 55 | # adapted from: 56 | # https://raw.githubusercontent.com/Itseez/opencv/master/samples/python2/hist.py 57 | 58 | 59 | def hist_lines(hist): 60 | h = np.ones((300, 256, 3)) * 255 # white background 61 | cv2.normalize(hist, hist, 0, 255, cv2.NORM_MINMAX) 62 | hist = np.int32(np.around(hist)) 63 | for x, y in enumerate(hist): 64 | y = y[0] 65 | cv2.line(h, (x, 0), (x, y), (0, 0, 0)) # black bars 66 | y = np.flipud(h) 67 | return y 68 | 69 | 70 | ##################################################################### 71 | 72 | # this function is called as a call-back everytime the trackbar is moved 73 | # (here we just do nothing) 74 | 75 | 76 | def nothing(x): 77 | pass 78 | 79 | 80 | ##################################################################### 81 | 82 | # define video capture object 83 | 84 | try: 85 | # to use a non-buffered camera stream (via a separate thread) 86 | 87 | if not (args.video_file): 88 | import camera_stream 89 | cap = camera_stream.CameraVideoStream(use_tapi=False) 90 | else: 91 | cap = cv2.VideoCapture() # not needed for video files 92 | 93 | except BaseException: 94 | # if not then just use OpenCV default 95 | 96 | print("INFO: camera_stream class not found - camera input may be buffered") 97 | cap = cv2.VideoCapture() 98 | 99 | # define display window name 100 | 101 | window_name1 = "Live Camera Input" # window name 102 | window_name2 = "Input Histogram" # window name 103 | window_name3 = "Processed Output" # window name 104 | window_name4 = "Output Histogram" # window name 105 | 106 | # if command line arguments are provided try to read video_file 107 | # otherwise default to capture from attached H/W camera 108 | 109 | if (((args.video_file) and (cap.open(str(args.video_file)))) 110 | or (cap.open(args.camera_to_use))): 111 | 112 | # create window by name (as resizable) 113 | 114 | cv2.namedWindow(window_name1, cv2.WINDOW_NORMAL) 115 | cv2.namedWindow(window_name2, cv2.WINDOW_NORMAL) 116 | cv2.namedWindow(window_name3, cv2.WINDOW_NORMAL) 117 | cv2.namedWindow(window_name4, cv2.WINDOW_NORMAL) 118 | 119 | # add some track bar controllers for settings 120 | 121 | clip_limit = 2 122 | cv2.createTrackbar("clip limit", window_name4, clip_limit, 25, nothing) 123 | tile_size = 8 124 | cv2.createTrackbar("tile size", window_name4, tile_size, 64, nothing) 125 | 126 | while (keep_processing): 127 | 128 | # if video file or camera successfully open then read frame from video 129 | 130 | if (cap.isOpened): 131 | ret, frame = cap.read() 132 | 133 | # when we reach the end of the video (file) exit cleanly 134 | 135 | if (ret == 0): 136 | keep_processing = False 137 | continue 138 | 139 | # rescale if specified 140 | 141 | if (args.rescale != 1.0): 142 | frame = cv2.resize( 143 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 144 | 145 | # convert to grayscale 146 | 147 | gray_img = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 148 | 149 | # perform contrast limited adaptive equalization 150 | # based on example at: 151 | # http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_equalization/py_histogram_equalization.html 152 | 153 | # get parameters from track bars 154 | 155 | clip_limit = cv2.getTrackbarPos("clip limit", window_name4) 156 | tile_size = cv2.getTrackbarPos("tile size", window_name4) 157 | 158 | # perform filtering 159 | 160 | clahe = cv2.createCLAHE( 161 | clipLimit=clip_limit, tileGridSize=( 162 | tile_size, tile_size)) # create filter 163 | output = clahe.apply(gray_img) # apply filter 164 | 165 | # display image 166 | 167 | cv2.imshow(window_name1, gray_img) 168 | cv2.imshow( 169 | window_name2, hist_lines( 170 | cv2.calcHist( 171 | [gray_img], [0], None, [256], [ 172 | 0, 256]))) 173 | cv2.imshow(window_name3, output) 174 | cv2.imshow( 175 | window_name4, hist_lines( 176 | cv2.calcHist( 177 | [output], [0], None, [256], [ 178 | 0, 256]))) 179 | 180 | # start the event loop - essential 181 | 182 | # cv2.waitKey() is a keyboard binding function (argument is the time in 183 | # ms). It waits for specified milliseconds for any keyboard event. 184 | # If you press any key in that time, the program continues. 185 | # If 0 is passed, it waits indefinitely for a key stroke. 186 | # (bitwise and with 0xFF to extract least significant byte of 187 | # multi-byte response) 188 | 189 | # wait 40ms (i.e. 1000ms / 25 fps = 40 ms) 190 | key = cv2.waitKey(40) & 0xFF 191 | 192 | # It can also be set to detect specific key strokes by recording which 193 | # key is pressed 194 | 195 | # e.g. if user presses "x" then exit 196 | 197 | if (key == ord('x')): 198 | keep_processing = False 199 | 200 | # close all windows 201 | 202 | cv2.destroyAllWindows() 203 | 204 | else: 205 | print("No video file specified or camera connected.") 206 | 207 | ##################################################################### 208 | -------------------------------------------------------------------------------- /colour_object_tracking.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : mean shift object tracking processing from a video file 4 | # specified on the command line (e.g. python FILE.py video_file) or from an 5 | # attached web camera 6 | 7 | # N.B. use mouse to select region 8 | 9 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 10 | 11 | # Copyright (c) 2015 School of Engineering & Computing Science, 12 | # Copyright (c) 2019 Dept Computer Science, 13 | # Durham University, UK 14 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 15 | 16 | # based in part on tutorial at: 17 | # http://docs.opencv.org/master/db/df8/tutorial_py_meanshift.html#gsc.tab=0 18 | 19 | ##################################################################### 20 | 21 | import cv2 22 | import argparse 23 | import sys 24 | import math 25 | import numpy as np 26 | 27 | ##################################################################### 28 | 29 | keep_processing = True 30 | 31 | # parse command line arguments for camera ID or video file 32 | 33 | parser = argparse.ArgumentParser( 34 | description='Perform ' + 35 | sys.argv[0] + 36 | ' example operation on incoming camera/video image') 37 | parser.add_argument( 38 | "-c", 39 | "--camera_to_use", 40 | type=int, 41 | help="specify camera to use", 42 | default=0) 43 | parser.add_argument( 44 | "-r", 45 | "--rescale", 46 | type=float, 47 | help="rescale image by this factor", 48 | default=1.0) 49 | parser.add_argument( 50 | 'video_file', 51 | metavar='video_file', 52 | type=str, 53 | nargs='?', 54 | help='specify optional video file') 55 | args = parser.parse_args() 56 | 57 | 58 | selection_in_progress = False # support interactive region selection 59 | 60 | ##################################################################### 61 | 62 | # select a region using the mouse 63 | 64 | boxes = [] 65 | current_mouse_position = np.ones(2, dtype=np.int32) 66 | 67 | 68 | def on_mouse(event, x, y, flags, params): 69 | 70 | global boxes 71 | global selection_in_progress 72 | 73 | current_mouse_position[0] = x 74 | current_mouse_position[1] = y 75 | 76 | if event == cv2.EVENT_LBUTTONDOWN: 77 | boxes = [] 78 | # print 'Start Mouse Position: '+str(x)+', '+str(y) 79 | sbox = [x, y] 80 | selection_in_progress = True 81 | boxes.append(sbox) 82 | 83 | elif event == cv2.EVENT_LBUTTONUP: 84 | # print 'End Mouse Position: '+str(x)+', '+str(y) 85 | ebox = [x, y] 86 | selection_in_progress = False 87 | boxes.append(ebox) 88 | 89 | 90 | ##################################################################### 91 | 92 | # this function is called as a call-back everytime the trackbar is moved 93 | # (here we just do nothing) 94 | 95 | def nothing(x): 96 | pass 97 | 98 | 99 | ##################################################################### 100 | 101 | # define video capture object 102 | 103 | try: 104 | # to use a non-buffered camera stream (via a separate thread) 105 | 106 | if not (args.video_file): 107 | import camera_stream 108 | cap = camera_stream.CameraVideoStream(use_tapi=False) 109 | else: 110 | cap = cv2.VideoCapture() # not needed for video files 111 | 112 | except BaseException: 113 | # if not then just use OpenCV default 114 | 115 | print("INFO: camera_stream class not found - camera input may be buffered") 116 | cap = cv2.VideoCapture() 117 | 118 | # define display window name 119 | 120 | window_name = "Live Camera Input" # window name 121 | window_name2 = "Hue histogram back projection" # window name 122 | window_name_selection = "selected" 123 | 124 | # if command line arguments are provided try to read video_file 125 | # otherwise default to capture from attached H/W camera 126 | 127 | if (((args.video_file) and (cap.open(str(args.video_file)))) 128 | or (cap.open(args.camera_to_use))): 129 | 130 | # create window by name (note flags for resizable or not) 131 | 132 | cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) 133 | cv2.namedWindow(window_name2, cv2.WINDOW_NORMAL) 134 | cv2.namedWindow(window_name_selection, cv2.WINDOW_NORMAL) 135 | 136 | # set sliders for HSV selection thresholds 137 | 138 | s_lower = 60 139 | cv2.createTrackbar("s lower", window_name2, s_lower, 255, nothing) 140 | s_upper = 255 141 | cv2.createTrackbar("s upper", window_name2, s_upper, 255, nothing) 142 | v_lower = 32 143 | cv2.createTrackbar("v lower", window_name2, v_lower, 255, nothing) 144 | v_upper = 255 145 | cv2.createTrackbar("v upper", window_name2, v_upper, 255, nothing) 146 | 147 | # set a mouse callback 148 | 149 | cv2.setMouseCallback(window_name, on_mouse, 0) 150 | cropped = False 151 | 152 | # Setup the termination criteria for search, either 10 iteration or 153 | # move by at least 1 pixel pos. difference 154 | term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1) 155 | 156 | while (keep_processing): 157 | 158 | # if video file or camera successfully open then read frame from video 159 | 160 | if (cap.isOpened): 161 | ret, frame = cap.read() 162 | 163 | # when we reach the end of the video (file) exit cleanly 164 | 165 | if (ret == 0): 166 | keep_processing = False 167 | continue 168 | 169 | # rescale if specified 170 | 171 | if (args.rescale != 1.0): 172 | frame = cv2.resize( 173 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 174 | 175 | # start a timer (to see how long processing and display takes) 176 | 177 | start_t = cv2.getTickCount() 178 | 179 | # get parameters from track bars 180 | 181 | s_lower = cv2.getTrackbarPos("s lower", window_name2) 182 | s_upper = cv2.getTrackbarPos("s upper", window_name2) 183 | v_lower = cv2.getTrackbarPos("v lower", window_name2) 184 | v_upper = cv2.getTrackbarPos("v upper", window_name2) 185 | 186 | # select region using the mouse and display it 187 | 188 | if (len(boxes) > 1) and (boxes[0][1] < boxes[1][1]) and ( 189 | boxes[0][0] < boxes[1][0]): 190 | crop = frame[boxes[0][1]:boxes[1][1], 191 | boxes[0][0]:boxes[1][0]].copy() 192 | 193 | h, w, c = crop.shape # size of template 194 | if (h > 0) and (w > 0): 195 | cropped = True 196 | 197 | # convert region to HSV 198 | 199 | hsv_crop = cv2.cvtColor(crop, cv2.COLOR_BGR2HSV) 200 | 201 | # select all Hue (0-> 180) and Sat. values but eliminate values 202 | # with very low saturation or value (due to lack of useful 203 | # colour information) 204 | 205 | mask = cv2.inRange( 206 | hsv_crop, np.array( 207 | (0., float(s_lower), float(v_lower))), np.array( 208 | (180., float(s_upper), float(v_upper)))) 209 | 210 | # construct a histogram of hue and saturation values and 211 | # normalize it 212 | 213 | crop_hist = cv2.calcHist( 214 | [hsv_crop], [ 215 | 0, 1], mask, [ 216 | 180, 255], [ 217 | 0, 180, 0, 255]) 218 | cv2.normalize(crop_hist, crop_hist, 0, 255, cv2.NORM_MINMAX) 219 | 220 | # set intial position of object 221 | 222 | track_window = ( 223 | boxes[0][0], 224 | boxes[0][1], 225 | boxes[1][0] - 226 | boxes[0][0], 227 | boxes[1][1] - 228 | boxes[0][1]) 229 | 230 | cv2.imshow(window_name_selection, crop) 231 | 232 | # reset list of boxes 233 | 234 | boxes = [] 235 | 236 | # interactive display of selection box 237 | 238 | if (selection_in_progress): 239 | top_left = (boxes[0][0], boxes[0][1]) 240 | bottom_right = ( 241 | current_mouse_position[0], 242 | current_mouse_position[1]) 243 | cv2.rectangle(frame, top_left, bottom_right, (0, 255, 0), 2) 244 | 245 | # if we have a selected region 246 | 247 | if (cropped): 248 | 249 | # convert incoming image to HSV 250 | 251 | img_hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) 252 | 253 | img_bproject = cv2.calcBackProject( 254 | [img_hsv], [ 255 | 0, 1], crop_hist, [ 256 | 0, 180, 0, 255], 1) 257 | cv2.imshow(window_name2, img_bproject) 258 | 259 | # apply meanshift to get the new location 260 | ret, track_window = cv2.meanShift( 261 | img_bproject, track_window, term_crit) 262 | 263 | # Draw it on image 264 | x, y, w, h = track_window 265 | frame = cv2.rectangle( 266 | frame, (x, y), (x + w, y + h), (255, 0, 0), 2) 267 | 268 | else: 269 | 270 | # before we have cropped anything show the mask we are using 271 | # for the S and V components of the HSV image 272 | 273 | img_hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) 274 | 275 | # select all Hue values (0-> 180) but eliminate values with very 276 | # low saturation or value (due to lack of useful colour info.) 277 | 278 | mask = cv2.inRange( 279 | img_hsv, np.array( 280 | (0., float(s_lower), float(v_lower))), np.array( 281 | (180., float(s_upper), float(v_upper)))) 282 | 283 | cv2.imshow(window_name2, mask) 284 | 285 | # display image 286 | 287 | cv2.imshow(window_name, frame) 288 | 289 | # stop the timer and convert to ms. (to see how long processing and 290 | # display takes) 291 | 292 | stop_t = ((cv2.getTickCount() - start_t) / 293 | cv2.getTickFrequency()) * 1000 294 | 295 | # start the event loop - essential 296 | 297 | # cv2.waitKey() is a keyboard binding function (argument is the time in 298 | # ms). It waits for specified milliseconds for any keyboard event. 299 | # If you press any key in that time, the program continues. 300 | # If 0 is passed, it waits indefinitely for a key stroke. 301 | # (bitwise and with 0xFF to extract least significant byte of 302 | # multi-byte response) 303 | 304 | # wait 40ms or less depending on processing time taken (i.e. 1000ms / 305 | # 25 fps = 40 ms) 306 | 307 | key = cv2.waitKey(max(2, 40 - int(math.ceil(stop_t)))) & 0xFF 308 | 309 | # It can also be set to detect specific key strokes by recording which 310 | # key is pressed 311 | 312 | # e.g. if user presses "x" then exit 313 | 314 | if (key == ord('x')): 315 | keep_processing = False 316 | 317 | # close all windows 318 | 319 | cv2.destroyAllWindows() 320 | 321 | else: 322 | print("No video file specified or camera connected.") 323 | 324 | ##################################################################### 325 | -------------------------------------------------------------------------------- /colour_query.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : displaying and interact with image from file 4 | 5 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 6 | 7 | # Copyright (c) 2015 School of Engineering & Computing Science, 8 | # Durham University, UK 9 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 10 | 11 | ##################################################################### 12 | 13 | import cv2 14 | 15 | ##################################################################### 16 | 17 | # mouse callback function - displays or sets image colour at the click 18 | # location of the mouse 19 | 20 | 21 | def colour_query_mouse_callback(event, x, y, flags, param): 22 | 23 | # records mouse events at postion (x,y) in the image window 24 | 25 | # left button click prints colour information at click location to stdout 26 | 27 | if event == cv2.EVENT_LBUTTONDOWN: 28 | print("BGR colour @ position (%d,%d) = %s" % 29 | (x, y, ', '.join(str(i) for i in img[y, x]))) 30 | 31 | # right button sets colour information at click location to white 32 | 33 | elif event == cv2.EVENT_RBUTTONDOWN: 34 | img[y, x] = [255, 255, 255] 35 | 36 | 37 | ##################################################################### 38 | 39 | # define display window name 40 | 41 | window_name = "Displayed Image" # window name 42 | 43 | # read an image from the specified file (in colour) 44 | 45 | img = cv2.imread('example.jpg', cv2.IMREAD_COLOR) 46 | 47 | # check it has loaded 48 | 49 | if img is not None: 50 | 51 | # create a named window object 52 | 53 | cv2.namedWindow(window_name) 54 | 55 | # set the mouse call back function that will be called every time 56 | # the mouse is clicked inside the associated window 57 | 58 | cv2.setMouseCallback(window_name, colour_query_mouse_callback) 59 | 60 | # set a loop control flag 61 | 62 | keep_processing = True 63 | 64 | while (keep_processing): 65 | 66 | # display this blurred image in a named window 67 | 68 | cv2.imshow(window_name, img) 69 | 70 | # start the event loop - essential 71 | 72 | # cv2.waitKey() is a keyboard binding function (argument is the time in 73 | # ms). It waits for specified milliseconds for any keyboard event. 74 | # If you press any key in that time, the program continues. 75 | # If 0 is passed, it waits indefinitely for a key stroke. 76 | # (bitwise and with 0xFF to extract least significant byte of 77 | # multi-byte response) 78 | 79 | # wait 40ms (i.e. 1000ms / 25 fps = 40 ms) 80 | key = cv2.waitKey(40) & 0xFF 81 | 82 | # It can also be set to detect specific key strokes by recording which 83 | # key is pressed 84 | 85 | # e.g. if user presses "x" then exit 86 | 87 | if (key == ord('x')): 88 | keep_processing = False 89 | 90 | else: 91 | print("No image file successfully loaded.") 92 | 93 | # ... and finally close all windows 94 | 95 | cv2.destroyAllWindows() 96 | 97 | ##################################################################### 98 | -------------------------------------------------------------------------------- /contrast_stretching.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : contrast stretching from a video file 4 | # specified on the command line (e.g. python FILE.py video_file) or from an 5 | # attached web camera 6 | 7 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 8 | 9 | # Copyright (c) 2015 School of Engineering & Computing Science, 10 | # Copyright (c) 2019 Dept Computer Science, 11 | # Durham University, UK 12 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 13 | 14 | ##################################################################### 15 | 16 | import cv2 17 | import argparse 18 | import numpy as np 19 | import sys 20 | 21 | ##################################################################### 22 | 23 | keep_processing = True 24 | 25 | # parse command line arguments for camera ID or video file 26 | 27 | parser = argparse.ArgumentParser( 28 | description='Perform ' + 29 | sys.argv[0] + 30 | ' example operation on incoming camera/video image') 31 | parser.add_argument( 32 | "-c", 33 | "--camera_to_use", 34 | type=int, 35 | help="specify camera to use", 36 | default=0) 37 | parser.add_argument( 38 | "-r", 39 | "--rescale", 40 | type=float, 41 | help="rescale image by this factor", 42 | default=1.0) 43 | parser.add_argument( 44 | 'video_file', 45 | metavar='video_file', 46 | type=str, 47 | nargs='?', 48 | help='specify optional video file') 49 | args = parser.parse_args() 50 | 51 | 52 | ##################################################################### 53 | 54 | # basic grayscale histogram drawing in raw OpenCV using lines 55 | 56 | # adapted from: 57 | # https://raw.githubusercontent.com/Itseez/opencv/master/samples/python2/hist.py 58 | 59 | def hist_lines(hist): 60 | h = np.ones((300, 256, 3)) * 255 # white background 61 | cv2.normalize(hist, hist, 0, 255, cv2.NORM_MINMAX) 62 | hist = np.int32(np.around(hist)) 63 | for x, y in enumerate(hist): 64 | y = y[0] 65 | cv2.line(h, (x, 0), (x, y), (0, 0, 0)) # black bars 66 | y = np.flipud(h) 67 | return y 68 | 69 | 70 | ##################################################################### 71 | 72 | # define video capture object 73 | 74 | try: 75 | # to use a non-buffered camera stream (via a separate thread) 76 | 77 | if not (args.video_file): 78 | import camera_stream 79 | cap = camera_stream.CameraVideoStream(use_tapi=False) 80 | else: 81 | cap = cv2.VideoCapture() # not needed for video files 82 | 83 | except BaseException: 84 | # if not then just use OpenCV default 85 | 86 | print("INFO: camera_stream class not found - camera input may be buffered") 87 | cap = cv2.VideoCapture() 88 | 89 | # define display window name 90 | 91 | window_name1 = "Live Camera Input" # window name 92 | window_name2 = "Input Histogram" # window name 93 | window_name3 = "Processed Output" # window name 94 | window_name4 = "Output Histogram" # window name 95 | 96 | # if command line arguments are provided try to read video_file 97 | # otherwise default to capture from attached H/W camera 98 | 99 | if (((args.video_file) and (cap.open(str(args.video_file)))) 100 | or (cap.open(args.camera_to_use))): 101 | 102 | # create window by name (as resizable) 103 | 104 | cv2.namedWindow(window_name1, cv2.WINDOW_NORMAL) 105 | cv2.namedWindow(window_name2, cv2.WINDOW_NORMAL) 106 | cv2.namedWindow(window_name3, cv2.WINDOW_NORMAL) 107 | cv2.namedWindow(window_name4, cv2.WINDOW_NORMAL) 108 | 109 | while (keep_processing): 110 | 111 | # if video file or camera successfully open then read frame from video 112 | 113 | if (cap.isOpened): 114 | ret, frame = cap.read() 115 | 116 | # when we reach the end of the video (file) exit cleanly 117 | 118 | if (ret == 0): 119 | keep_processing = False 120 | continue 121 | 122 | # rescale if specified 123 | 124 | if (args.rescale != 1.0): 125 | frame = cv2.resize( 126 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 127 | 128 | # convert to grayscale 129 | 130 | gray_img = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 131 | 132 | # create an empty image of the same size for the output 133 | 134 | output = np.empty(gray_img.shape, dtype=np.uint8) 135 | 136 | # perform basic contrast stretching 137 | 138 | # cv2.normalize() with these parameters does 139 | # basic constrast stretching 140 | 141 | cv2.normalize( 142 | gray_img, 143 | output, 144 | alpha=0, 145 | beta=255, 146 | norm_type=cv2.NORM_MINMAX) 147 | 148 | # display image 149 | 150 | cv2.imshow(window_name1, gray_img) 151 | cv2.imshow( 152 | window_name2, hist_lines( 153 | cv2.calcHist( 154 | [gray_img], [0], None, [256], [ 155 | 0, 256]))) 156 | cv2.imshow(window_name3, output) 157 | cv2.imshow( 158 | window_name4, hist_lines( 159 | cv2.calcHist( 160 | [output], [0], None, [256], [ 161 | 0, 256]))) 162 | 163 | # start the event loop - essential 164 | 165 | # cv2.waitKey() is a keyboard binding function (argument is the time in 166 | # ms). It waits for specified milliseconds for any keyboard event. 167 | # If you press any key in that time, the program continues. 168 | # If 0 is passed, it waits indefinitely for a key stroke. 169 | # (bitwise and with 0xFF to extract least significant byte of 170 | # multi-byte response) 171 | 172 | # wait 40ms (i.e. 1000ms / 25 fps = 40 ms) 173 | key = cv2.waitKey(40) & 0xFF 174 | 175 | # It can also be set to detect specific key strokes by recording which 176 | # key is pressed 177 | 178 | # e.g. if user presses "x" then exit 179 | 180 | if (key == ord('x')): 181 | keep_processing = False 182 | 183 | # close all windows 184 | 185 | cv2.destroyAllWindows() 186 | 187 | else: 188 | print("No video file specified or camera connected.") 189 | 190 | ##################################################################### 191 | -------------------------------------------------------------------------------- /correlation_template_matching.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : live template matching via processing from a video file 4 | # specified on the command line (e.g. python FILE.py video_file) or from an 5 | # attached web camera 6 | 7 | # N.B. use mouse to select region 8 | 9 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 10 | 11 | # Copyright (c) 2015 School of Engineering & Computing Science, 12 | # Copyright (c) 2019 Dept Computer Science, 13 | # Durham University, UK 14 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 15 | 16 | # version 0.2 17 | 18 | ##################################################################### 19 | 20 | import cv2 21 | import argparse 22 | import sys 23 | import math 24 | import numpy as np 25 | 26 | ##################################################################### 27 | 28 | keep_processing = True 29 | 30 | # parse command line arguments for camera ID or video file 31 | 32 | parser = argparse.ArgumentParser( 33 | description='Perform ' + 34 | sys.argv[0] + 35 | ' example operation on incoming camera/video image') 36 | parser.add_argument( 37 | "-c", 38 | "--camera_to_use", 39 | type=int, 40 | help="specify camera to use", 41 | default=0) 42 | parser.add_argument( 43 | "-r", 44 | "--rescale", 45 | type=float, 46 | help="rescale image by this factor", 47 | default=1.0) 48 | parser.add_argument( 49 | 'video_file', 50 | metavar='video_file', 51 | type=str, 52 | nargs='?', 53 | help='specify optional video file') 54 | args = parser.parse_args() 55 | 56 | 57 | selection_in_progress = False # support interactive region selection 58 | 59 | ##################################################################### 60 | 61 | # select a region using the mouse 62 | 63 | boxes = [] 64 | current_mouse_position = np.ones(2, dtype=np.int32) 65 | 66 | 67 | def on_mouse(event, x, y, flags, params): 68 | 69 | global boxes 70 | global selection_in_progress 71 | 72 | current_mouse_position[0] = x 73 | current_mouse_position[1] = y 74 | 75 | if event == cv2.EVENT_LBUTTONDOWN: 76 | boxes = [] 77 | # print 'Start Mouse Position: '+str(x)+', '+str(y) 78 | sbox = [x, y] 79 | selection_in_progress = True 80 | boxes.append(sbox) 81 | 82 | elif event == cv2.EVENT_LBUTTONUP: 83 | # print 'End Mouse Position: '+str(x)+', '+str(y) 84 | ebox = [x, y] 85 | selection_in_progress = False 86 | boxes.append(ebox) 87 | 88 | 89 | ##################################################################### 90 | 91 | # define video capture object 92 | 93 | try: 94 | # to use a non-buffered camera stream (via a separate thread) 95 | 96 | if not (args.video_file): 97 | import camera_stream 98 | cap = camera_stream.CameraVideoStream(use_tapi=False) 99 | else: 100 | cap = cv2.VideoCapture() # not needed for video files 101 | 102 | except BaseException: 103 | # if not then just use OpenCV default 104 | 105 | print("INFO: camera_stream class not found - camera input may be buffered") 106 | cap = cv2.VideoCapture() 107 | 108 | # define display window name 109 | 110 | window_name = "Live Camera Input" # window name 111 | window_name2 = "Correlation Output" # window name 112 | window_name_selection = "selected" 113 | 114 | # if command line arguments are provided try to read video_file 115 | # otherwise default to capture from attached H/W camera 116 | 117 | if (((args.video_file) and (cap.open(str(args.video_file)))) 118 | or (cap.open(args.camera_to_use))): 119 | 120 | # create window by name (note flags for resizable or not) 121 | 122 | cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) 123 | cv2.namedWindow(window_name2, cv2.WINDOW_NORMAL) 124 | cv2.namedWindow(window_name_selection, cv2.WINDOW_NORMAL) 125 | 126 | # set a mouse callback 127 | 128 | cv2.setMouseCallback(window_name, on_mouse, 0) 129 | cropped = False 130 | 131 | # usage 132 | 133 | print("USAGE: click and drag left to right to select an image region") 134 | 135 | while (keep_processing): 136 | 137 | # if video file or camera successfully open then read frame from video 138 | 139 | if (cap.isOpened): 140 | ret, frame = cap.read() 141 | 142 | # when we reach the end of the video (file) exit cleanly 143 | 144 | if (ret == 0): 145 | keep_processing = False 146 | continue 147 | 148 | # rescale if specified 149 | 150 | if (args.rescale != 1.0): 151 | frame = cv2.resize( 152 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 153 | 154 | # start a timer (to see how long processing and display takes) 155 | 156 | start_t = cv2.getTickCount() 157 | 158 | # select region using the mouse and display it 159 | 160 | if (len(boxes) > 1) and (boxes[0][1] < boxes[1][1]) and ( 161 | boxes[0][0] < boxes[1][0]): 162 | crop = frame[boxes[0][1]:boxes[1][1], 163 | boxes[0][0]:boxes[1][0]].copy() 164 | boxes = [] 165 | h, w, c = crop.shape # size of template 166 | if (h > 0) and (w > 0): 167 | cropped = True 168 | cv2.imshow(window_name_selection, crop) 169 | 170 | # interactive display of selection box 171 | 172 | if (selection_in_progress): 173 | top_left = (boxes[0][0], boxes[0][1]) 174 | bottom_right = ( 175 | current_mouse_position[0], 176 | current_mouse_position[1]) 177 | cv2.rectangle(frame, top_left, bottom_right, (0, 255, 0), 2) 178 | 179 | # if we have cropped a region perform template matching using 180 | # (normalized) cross correlation and draw rectangle around best match 181 | 182 | if cropped: 183 | correlation = cv2.matchTemplate(frame, crop, cv2.TM_CCOEFF_NORMED) 184 | min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(correlation) 185 | h, w, c = crop.shape # size of template 186 | top_left = max_loc # top left of template matching image frame 187 | bottom_right = (top_left[0] + w, top_left[1] + h) 188 | cv2.rectangle(frame, top_left, bottom_right, (0, 0, 255), 2) 189 | 190 | cv2.imshow(window_name2, correlation) 191 | 192 | # display image 193 | 194 | cv2.imshow(window_name, frame) 195 | 196 | # stop the timer and convert to ms. (to see how long processing and 197 | # display takes) 198 | 199 | stop_t = ((cv2.getTickCount() - start_t) / 200 | cv2.getTickFrequency()) * 1000 201 | 202 | # start the event loop - essential 203 | 204 | # cv2.waitKey() is a keyboard binding function (argument is the time in 205 | # ms). It waits for specified milliseconds for any keyboard event. 206 | # If you press any key in that time, the program continues. 207 | # If 0 is passed, it waits indefinitely for a key stroke. 208 | # (bitwise and with 0xFF to extract least significant byte of 209 | # multi-byte response) 210 | 211 | # wait 40ms or less depending on processing time taken (i.e. 1000ms / 212 | # 25 fps = 40 ms) 213 | 214 | key = cv2.waitKey(max(2, 40 - int(math.ceil(stop_t)))) & 0xFF 215 | 216 | # It can also be set to detect specific key strokes by recording which 217 | # key is pressed 218 | 219 | # e.g. if user presses "x" then exit 220 | 221 | if (key == ord('x')): 222 | keep_processing = False 223 | 224 | # close all windows 225 | 226 | cv2.destroyAllWindows() 227 | 228 | else: 229 | print("No video file specified or camera connected.") 230 | 231 | ##################################################################### 232 | -------------------------------------------------------------------------------- /dct_low_pass_filter.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : perform low pass filterings in DCT space of image frame 4 | # from a video file specified on the command line (e.g. python FILE.py 5 | # video_file) or from an attached web camera 6 | 7 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 8 | 9 | # Copyright (c) 2015 School of Engineering & Computing Science, 10 | # Copyright (c) 2019 Dept Computer Science, 11 | # Durham University, UK 12 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 13 | 14 | ##################################################################### 15 | 16 | import cv2 17 | import argparse 18 | import sys 19 | import numpy as np 20 | import math 21 | 22 | ##################################################################### 23 | 24 | keep_processing = True 25 | 26 | # parse command line arguments for camera ID or video file 27 | 28 | parser = argparse.ArgumentParser( 29 | description='Perform ' + 30 | sys.argv[0] + 31 | ' example operation on incoming camera/video image') 32 | parser.add_argument( 33 | "-c", 34 | "--camera_to_use", 35 | type=int, 36 | help="specify camera to use", 37 | default=0) 38 | parser.add_argument( 39 | "-r", 40 | "--rescale", 41 | type=float, 42 | help="rescale image by this factor", 43 | default=1.0) 44 | parser.add_argument( 45 | 'video_file', 46 | metavar='video_file', 47 | type=str, 48 | nargs='?', 49 | help='specify optional video file') 50 | args = parser.parse_args() 51 | 52 | 53 | ##################################################################### 54 | 55 | # create a simple low pass filter - DCT version (top left corner) 56 | 57 | def create_low_pass_filter(width, height, radius): 58 | lp_filter = np.zeros((height, width), np.float32) 59 | cv2.circle(lp_filter, (0, 0), radius, (1, 1, 1), thickness=-1) 60 | return lp_filter 61 | 62 | ##################################################################### 63 | 64 | # "Currently dct supports even-size arrays (2, 4, 6 ...). For data 65 | # analysis and approximation, you can pad the array when necessary. 66 | # Also, the function performance depends very much, and not 67 | # monotonically, on the array size (see getOptimalDFTSize() ). In the 68 | # current implementation DCT of a vector of size N is calculated 69 | # via DFT of a vector of size N/2 . Thus, the optimal DCT 70 | # size N1 >= N can be calculated as:" - OpenCV manual 3.0 71 | 72 | 73 | def get_optimal_dct_size(n): 74 | return (2 * cv2.getOptimalDFTSize(math.floor((n + 1) / 2))) 75 | 76 | 77 | ##################################################################### 78 | 79 | # this function is called as a call-back everytime the trackbar is moved 80 | # (here we just do nothing) 81 | 82 | def nothing(x): 83 | pass 84 | 85 | 86 | ##################################################################### 87 | 88 | # define video capture object 89 | 90 | try: 91 | # to use a non-buffered camera stream (via a separate thread) 92 | 93 | if not (args.video_file): 94 | import camera_stream 95 | cap = camera_stream.CameraVideoStream(use_tapi=False) 96 | else: 97 | cap = cv2.VideoCapture() # not needed for video files 98 | 99 | except BaseException: 100 | # if not then just use OpenCV default 101 | 102 | print("INFO: camera_stream class not found - camera input may be buffered") 103 | cap = cv2.VideoCapture() 104 | 105 | # define display window name 106 | 107 | window_name = "Live Camera Input" # window name 108 | window_name2 = "DCT Co-efficients Spectrum" # window name 109 | window_name3 = "Filtered Image" # window name 110 | 111 | # if command line arguments are provided try to read video_file 112 | # otherwise default to capture from attached H/W camera 113 | 114 | if (((args.video_file) and (cap.open(str(args.video_file)))) 115 | or (cap.open(args.camera_to_use))): 116 | 117 | # create windows by name (as resizable) 118 | 119 | cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) 120 | cv2.namedWindow(window_name2, cv2.WINDOW_NORMAL) 121 | cv2.namedWindow(window_name3, cv2.WINDOW_NORMAL) 122 | 123 | # if video file or camera successfully open then read frame from video 124 | 125 | if (cap.isOpened): 126 | ret, frame = cap.read() 127 | 128 | # rescale if specified 129 | 130 | if (args.rescale != 1.0): 131 | frame = cv2.resize(frame, (0, 0), fx=args.rescale, fy=args.rescale) 132 | 133 | # convert to grayscale 134 | 135 | gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 136 | 137 | # use this single frame to set up optimized DFT settings 138 | 139 | height, width = gray_frame.shape 140 | nheight = get_optimal_dct_size(height) 141 | nwidth = get_optimal_dct_size(width) 142 | 143 | # add some track bar controllers for settings 144 | 145 | radius = 25 146 | cv2.createTrackbar( 147 | "radius", window_name2, radius, max( 148 | nheight, nwidth) * 2, nothing) 149 | 150 | while (keep_processing): 151 | 152 | # if video file or camera successfully open then read frame from video 153 | 154 | if (cap.isOpened): 155 | ret, frame = cap.read() 156 | 157 | # when we reach the end of the video (file) exit cleanly 158 | 159 | if (ret == 0): 160 | keep_processing = False 161 | continue 162 | 163 | # rescale if specified 164 | 165 | if (args.rescale != 1.0): 166 | frame = cv2.resize( 167 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 168 | 169 | # start a timer (to see how long processing and display takes) 170 | 171 | start_t = cv2.getTickCount() 172 | 173 | # convert to grayscale 174 | 175 | gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 176 | 177 | # Performance of DCT calculation, via the DFT/FFT, is better for array 178 | # sizes of power of two. Arrays whose size is a product of 2's, 3's, 179 | # and 5's are also processed quite efficiently. 180 | # Hence we modify the size of the array tothe optimal size (by padding 181 | # zeros) before finding DCT. 182 | 183 | pad_right = nwidth - width 184 | pad_bottom = nheight - height 185 | nframe = cv2.copyMakeBorder( 186 | gray_frame, 187 | 0, 188 | pad_bottom, 189 | 0, 190 | pad_right, 191 | cv2.BORDER_CONSTANT, 192 | value=0) 193 | 194 | # perform the DCT 195 | 196 | dct = cv2.dct(np.float32(nframe)) 197 | 198 | # perform low pass filtering 199 | 200 | radius = cv2.getTrackbarPos("radius", window_name2) 201 | lp_filter = create_low_pass_filter(nwidth, nheight, radius) 202 | 203 | dct_filtered = cv2.multiply(dct, lp_filter) 204 | 205 | # recover the original image via the inverse DCT 206 | 207 | filtered_img = cv2.dct(dct_filtered, flags=cv2.DCT_INVERSE) 208 | 209 | # normalized the filtered image into 0 -> 255 (8-bit grayscale) so we 210 | # can see the output 211 | 212 | min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(filtered_img) 213 | filtered_img_normalized = filtered_img * \ 214 | (1.0 / (max_val - min_val)) + ((-min_val) / (max_val - min_val)) 215 | filtered_img_normalized = np.uint8(filtered_img_normalized * 255) 216 | 217 | # calculate the DCT spectrum for visualization 218 | 219 | # create a 8-bit image to put the magnitude spectrum into 220 | 221 | dct_spectrum_normalized = np.zeros((nheight, nwidth, 1), np.uint8) 222 | 223 | # normalized the magnitude spectrum into 0 -> 255 (8-bit grayscale) so 224 | # we can see the output 225 | 226 | cv2.normalize( 227 | np.uint8(dct_filtered), 228 | dct_spectrum_normalized, 229 | alpha=0, 230 | beta=255, 231 | norm_type=cv2.NORM_MINMAX) 232 | 233 | # display images 234 | 235 | cv2.imshow(window_name, gray_frame) 236 | cv2.imshow(window_name2, dct_spectrum_normalized) 237 | cv2.imshow(window_name3, filtered_img_normalized) 238 | 239 | # stop timer and convert to ms. (to see how long processing and display 240 | # takes) 241 | 242 | stop_t = ((cv2.getTickCount() - start_t) / 243 | cv2.getTickFrequency()) * 1000 244 | 245 | # start the event loop - essential 246 | 247 | # cv2.waitKey() is a keyboard binding function (argument is the time in 248 | # ms). It waits for specified milliseconds for any keyboard event. 249 | # If you press any key in that time, the program continues. 250 | # If 0 is passed, it waits indefinitely for a key stroke. 251 | # (bitwise and with 0xFF to extract least significant byte of 252 | # multi-byte response) 253 | 254 | # here we use a wait time in ms. that takes account of processing time 255 | # already used in the loop 256 | 257 | # wait 40ms (i.e. 1000ms / 25 fps = 40 ms) 258 | key = cv2.waitKey(max(2, 40 - int(math.ceil(stop_t)))) & 0xFF 259 | 260 | # It can also be set to detect specific key strokes by recording which 261 | # key is pressed 262 | 263 | # e.g. if user presses "x" then exit 264 | 265 | if (key == ord('x')): 266 | keep_processing = False 267 | 268 | # close all windows 269 | 270 | cv2.destroyAllWindows() 271 | 272 | else: 273 | print("No video file specified or camera connected.") 274 | 275 | ##################################################################### 276 | -------------------------------------------------------------------------------- /exponential.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : exponential transform on an image from an attached web camera 4 | 5 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 6 | 7 | # Copyright (c) 2015 School of Engineering & Computing Science, 8 | # Copyright (c) 2019 Dept Computer Science, 9 | # Durham University, UK 10 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 11 | 12 | ##################################################################### 13 | 14 | import cv2 15 | import sys 16 | import argparse 17 | import math 18 | 19 | ##################################################################### 20 | 21 | keep_processing = True 22 | 23 | # parse command line arguments for camera ID or video file 24 | 25 | parser = argparse.ArgumentParser( 26 | description='Perform ' + 27 | sys.argv[0] + 28 | ' example operation on incoming camera/video image') 29 | parser.add_argument( 30 | "-c", 31 | "--camera_to_use", 32 | type=int, 33 | help="specify camera to use", 34 | default=0) 35 | parser.add_argument( 36 | "-r", 37 | "--rescale", 38 | type=float, 39 | help="rescale image by this factor", 40 | default=1.0) 41 | parser.add_argument( 42 | 'video_file', 43 | metavar='video_file', 44 | type=str, 45 | nargs='?', 46 | help='specify optional video file') 47 | args = parser.parse_args() 48 | 49 | 50 | ##################################################################### 51 | 52 | # this function is called as a call-back everytime the trackbar is moved 53 | # (here we just do nothing) 54 | 55 | def nothing(x): 56 | pass 57 | 58 | 59 | ##################################################################### 60 | 61 | # exponential transform 62 | # image - greyscale image 63 | # c - scaling constant 64 | # alpha - "gradient" co-efficient of exponential function 65 | 66 | def exponential_transform(image, c, alpha): 67 | for i in range(0, image.shape[1]): # image width 68 | for j in range(0, image.shape[0]): # image height 69 | 70 | # compute exponential transform 71 | 72 | image[j, i] = int(c * (math.pow(1 + alpha, image[j, i]) - 1)) 73 | return image 74 | 75 | 76 | ##################################################################### 77 | 78 | # define video capture object 79 | 80 | try: 81 | # to use a non-buffered camera stream (via a separate thread) 82 | 83 | if not (args.video_file): 84 | import camera_stream 85 | cap = camera_stream.CameraVideoStream(use_tapi=False) 86 | else: 87 | cap = cv2.VideoCapture() # not needed for video files 88 | 89 | except BaseException: 90 | # if not then just use OpenCV default 91 | 92 | print("INFO: camera_stream class not found - camera input may be buffered") 93 | cap = cv2.VideoCapture() 94 | 95 | # define display window name 96 | 97 | window_name = "Live Camera Input" # window name 98 | window_name2 = "Exponential Transform" # window name 99 | 100 | # if command line arguments are provided try to read video_file 101 | # otherwise default to capture from attached H/W camera 102 | 103 | if (((args.video_file) and (cap.open(str(args.video_file)))) 104 | or (cap.open(args.camera_to_use))): 105 | 106 | # create window by name (as resizable) 107 | 108 | cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) 109 | cv2.namedWindow(window_name2, cv2.WINDOW_NORMAL) 110 | 111 | # add some track bar controllers for settings 112 | 113 | constant = 10 114 | cv2.createTrackbar("constant, C", window_name2, constant, 100, nothing) 115 | 116 | alpha = 10 117 | cv2.createTrackbar("alpha (*0.001)", window_name2, alpha, 50, nothing) 118 | 119 | while (keep_processing): 120 | 121 | # if video file or camera successfully open then read frame from video 122 | 123 | if (cap.isOpened): 124 | ret, frame = cap.read() 125 | 126 | # when we reach the end of the video (file) exit cleanly 127 | 128 | if (ret == 0): 129 | keep_processing = False 130 | continue 131 | 132 | # rescale if specified 133 | 134 | if (args.rescale != 1.0): 135 | frame = cv2.resize( 136 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 137 | 138 | # convert to grayscale 139 | 140 | gray_img = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 141 | 142 | # get parameters from track bars 143 | 144 | constant = cv2.getTrackbarPos("constant, C", window_name2) 145 | alpha = cv2.getTrackbarPos("alpha (*0.001)", window_name2) * 0.001 146 | 147 | # make a copy and exp tranform it 148 | 149 | exp_img = gray_img.copy() 150 | exp_img = exponential_transform(exp_img, constant, alpha) 151 | 152 | # display image 153 | 154 | cv2.imshow(window_name, gray_img) 155 | cv2.imshow(window_name2, exp_img) 156 | 157 | # start the event loop - essential 158 | 159 | # cv2.waitKey() is a keyboard binding function (argument is the time in 160 | # ms). It waits for specified milliseconds for any keyboard event. 161 | # If you press any key in that time, the program continues. 162 | # If 0 is passed, it waits indefinitely for a key stroke. 163 | # (bitwise and with 0xFF to extract least significant byte of 164 | # multi-byte response) 165 | 166 | # wait 40ms (i.e. 1000ms / 25 fps = 40 ms) 167 | key = cv2.waitKey(40) & 0xFF 168 | 169 | # It can also be set to detect specific key strokes by recording which 170 | # key is pressed 171 | 172 | # e.g. if user presses "x" then exit 173 | 174 | if (key == ord('x')): 175 | keep_processing = False 176 | 177 | # close all windows 178 | 179 | cv2.destroyAllWindows() 180 | 181 | else: 182 | print("No usable camera connected.") 183 | 184 | 185 | ##################################################################### 186 | -------------------------------------------------------------------------------- /fourier.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : display fourier magnitude spectrum of image frame from a 4 | # video file specified on the command line (e.g. python FILE.py 5 | # video_file) or from an attached web camera 6 | 7 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 8 | # Copyright (c) 2015 School of Engineering & Computing Science, 9 | # Copyright (c) 2019 Dept Computer Science, 10 | # Durham University, UK 11 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 12 | 13 | ##################################################################### 14 | 15 | import cv2 16 | import argparse 17 | import sys 18 | import numpy as np 19 | import math 20 | 21 | ##################################################################### 22 | 23 | # ignore divide by zero errors in np.log() operations 24 | 25 | np.seterr(divide='ignore') 26 | 27 | ##################################################################### 28 | 29 | keep_processing = True 30 | 31 | # parse command line arguments for camera ID or video file 32 | 33 | parser = argparse.ArgumentParser( 34 | description='Perform ' + 35 | sys.argv[0] + 36 | ' example operation on incoming camera/video image') 37 | parser.add_argument( 38 | "-c", 39 | "--camera_to_use", 40 | type=int, 41 | help="specify camera to use", 42 | default=0) 43 | parser.add_argument( 44 | "-r", 45 | "--rescale", 46 | type=float, 47 | help="rescale image by this factor", 48 | default=1.0) 49 | parser.add_argument( 50 | 'video_file', 51 | metavar='video_file', 52 | type=str, 53 | nargs='?', 54 | help='specify optional video file') 55 | args = parser.parse_args() 56 | 57 | 58 | ##################################################################### 59 | 60 | # define video capture object 61 | 62 | try: 63 | # to use a non-buffered camera stream (via a separate thread) 64 | 65 | if not (args.video_file): 66 | import camera_stream 67 | cap = camera_stream.CameraVideoStream(use_tapi=False) 68 | else: 69 | cap = cv2.VideoCapture() # not needed for video files 70 | 71 | except BaseException: 72 | # if not then just use OpenCV default 73 | 74 | print("INFO: camera_stream class not found - camera input may be buffered") 75 | cap = cv2.VideoCapture() 76 | 77 | # define display window name 78 | 79 | window_name = "Live Camera Input" # window name 80 | window_name2 = "Fourier Magnitude Spectrum" # window name 81 | 82 | 83 | # if command line arguments are provided try to read video_file 84 | # otherwise default to capture from attached H/W camera 85 | 86 | if (((args.video_file) and (cap.open(str(args.video_file)))) 87 | or (cap.open(args.camera_to_use))): 88 | 89 | # create windows by name (as resizable) 90 | 91 | cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) 92 | cv2.namedWindow(window_name2, cv2.WINDOW_NORMAL) 93 | 94 | # if video file or camera successfully open then read frame from video 95 | 96 | if (cap.isOpened): 97 | ret, frame = cap.read() 98 | 99 | # rescale if specified 100 | 101 | if (args.rescale != 1.0): 102 | frame = cv2.resize(frame, (0, 0), fx=args.rescale, fy=args.rescale) 103 | 104 | # convert to grayscale 105 | 106 | gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 107 | 108 | # use this single frame to set up optimized DFT settings 109 | 110 | hieght, width = gray_frame.shape 111 | nhieght = cv2.getOptimalDFTSize(hieght) 112 | nwidth = cv2.getOptimalDFTSize(width) 113 | 114 | while (keep_processing): 115 | 116 | # if video file or camera successfully open then read frame from video 117 | 118 | if (cap.isOpened): 119 | ret, frame = cap.read() 120 | 121 | # when we reach the end of the video (file) exit cleanly 122 | 123 | if (ret == 0): 124 | keep_processing = False 125 | continue 126 | 127 | # rescale if specified 128 | 129 | if (args.rescale != 1.0): 130 | frame = cv2.resize( 131 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 132 | 133 | # start a timer (to see how long processing and display takes) 134 | 135 | start_t = cv2.getTickCount() 136 | 137 | # convert to grayscale 138 | 139 | gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 140 | 141 | # Performance of DFT calculation, via the FFT, is better for array 142 | # sizes of power of two. Arrays whose size is a product of 143 | # 2's, 3's, and 5's are also processed quite efficiently. 144 | # Hence we modify the size of the array to the optimal size (by padding 145 | # zeros) before finding DFT. 146 | 147 | pad_right = nwidth - width 148 | pad_bottom = nhieght - hieght 149 | nframe = cv2.copyMakeBorder( 150 | gray_frame, 151 | 0, 152 | pad_bottom, 153 | 0, 154 | pad_right, 155 | cv2.BORDER_CONSTANT, 156 | value=0) 157 | 158 | # perform the DFT and get complex output 159 | 160 | dft = cv2.dft(np.float32(nframe), flags=cv2.DFT_COMPLEX_OUTPUT) 161 | 162 | # shift it so that we the zero-frequency, F(0,0), DC component to the 163 | # center of the spectrum. 164 | 165 | dft_shifted = np.fft.fftshift(dft) 166 | 167 | # calculate the magnitude spectrum and log transform + scale it for 168 | # visualization 169 | 170 | magnitude_spectrum = np.log(cv2.magnitude( 171 | dft_shifted[:, :, 0], dft_shifted[:, :, 1])) 172 | 173 | # create a 8-bit image to put the magnitude spectrum into 174 | 175 | magnitude_spectrum_normalized = np.zeros( 176 | (nhieght, nwidth, 1), np.uint8) 177 | 178 | # normalized the magnitude spectrum into 0 -> 255 (8-bit grayscale) so 179 | # we can see the output 180 | 181 | cv2.normalize( 182 | np.uint8(magnitude_spectrum), 183 | magnitude_spectrum_normalized, 184 | alpha=0, 185 | beta=255, 186 | norm_type=cv2.NORM_MINMAX) 187 | 188 | # display images 189 | 190 | cv2.imshow(window_name, gray_frame) 191 | cv2.imshow(window_name2, magnitude_spectrum_normalized) 192 | 193 | # stop timer and convert to ms. (to see how long processing and display 194 | # takes) 195 | 196 | stop_t = ((cv2.getTickCount() - start_t) / 197 | cv2.getTickFrequency()) * 1000 198 | 199 | # start the event loop - essential 200 | 201 | # cv2.waitKey() is a keyboard binding function (argument is the time in 202 | # ms). It waits for specified milliseconds for any keyboard event. 203 | # If you press any key in that time, the program continues. 204 | # If 0 is passed, it waits indefinitely for a key stroke. 205 | # (bitwise and with 0xFF to extract least significant byte of 206 | # multi-byte response) 207 | 208 | # here we use a wait time in ms. that takes account of processing time 209 | # already used in the loop 210 | 211 | # wait 40ms (i.e. 1000ms / 25 fps = 40 ms) 212 | key = cv2.waitKey(max(2, 40 - int(math.ceil(stop_t)))) & 0xFF 213 | 214 | # It can also be set to detect specific key strokes by recording which 215 | # key is pressed 216 | 217 | # e.g. if user presses "x" then exit 218 | 219 | if (key == ord('x')): 220 | keep_processing = False 221 | 222 | # close all windows 223 | 224 | cv2.destroyAllWindows() 225 | 226 | else: 227 | print("No video file specified or camera connected.") 228 | 229 | ##################################################################### 230 | -------------------------------------------------------------------------------- /gamma.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : gamma correction /power-law transform on an image 4 | # from an attached web camera (or video file specified on command line) 5 | 6 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 7 | 8 | # Copyright (c) 2015 School of Engineering & Computing Science, 9 | # Copyright (c) 2019 Dept Computer Science, 10 | # Durham University, UK 11 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 12 | 13 | ##################################################################### 14 | 15 | import cv2 16 | import argparse 17 | import sys 18 | import numpy as np 19 | 20 | ##################################################################### 21 | 22 | keep_processing = True 23 | 24 | # parse command line arguments for camera ID or video file 25 | 26 | parser = argparse.ArgumentParser( 27 | description='Perform ' + 28 | sys.argv[0] + 29 | ' example operation on incoming camera/video image') 30 | parser.add_argument( 31 | "-c", 32 | "--camera_to_use", 33 | type=int, 34 | help="specify camera to use", 35 | default=0) 36 | parser.add_argument( 37 | "-r", 38 | "--rescale", 39 | type=float, 40 | help="rescale image by this factor", 41 | default=1.0) 42 | parser.add_argument( 43 | 'video_file', 44 | metavar='video_file', 45 | type=str, 46 | nargs='?', 47 | help='specify optional video file') 48 | args = parser.parse_args() 49 | 50 | 51 | ##################################################################### 52 | 53 | # this function is called as a call-back everytime the trackbar is moved 54 | # (here we just do nothing) 55 | 56 | def nothing(x): 57 | pass 58 | 59 | 60 | ##################################################################### 61 | 62 | # power law transform 63 | # image - colour image 64 | # gamma - "gradient" co-efficient of gamma function 65 | 66 | 67 | def powerlaw_transform(image, gamma): 68 | 69 | # compute power-law transform 70 | # remembering not defined for pixel = 0 (!) 71 | 72 | # handle any overflow in a quick and dirty way using 0-255 clipping 73 | 74 | image = np.clip(np.power(image, gamma), 0, 255).astype('uint8') 75 | 76 | return image 77 | 78 | 79 | ##################################################################### 80 | 81 | # define video capture object 82 | 83 | try: 84 | # to use a non-buffered camera stream (via a separate thread) 85 | 86 | if not (args.video_file): 87 | import camera_stream 88 | cap = camera_stream.CameraVideoStream(use_tapi=False) 89 | else: 90 | cap = cv2.VideoCapture() # not needed for video files 91 | 92 | except BaseException: 93 | # if not then just use OpenCV default 94 | 95 | print("INFO: camera_stream class not found - camera input may be buffered") 96 | cap = cv2.VideoCapture() 97 | 98 | # define display window name 99 | 100 | window_name = "Live Camera Input" # window name 101 | window_name2 = "Gamma Corrected (Power-Law Transform)" # window name 102 | 103 | # if command line arguments are provided try to read video_file 104 | # otherwise default to capture from attached H/W camera 105 | 106 | if (((args.video_file) and (cap.open(str(args.video_file)))) 107 | or (cap.open(args.camera_to_use))): 108 | 109 | # create window by name (as resizable) 110 | 111 | cv2.namedWindow(window_name, cv2.WINDOW_AUTOSIZE) 112 | cv2.namedWindow(window_name2, cv2.WINDOW_AUTOSIZE) 113 | 114 | # add some track bar controllers for settings 115 | 116 | gamma = 100 # default gamma - no change 117 | 118 | cv2.createTrackbar("gamma, (* 0.01)", window_name2, gamma, 500, nothing) 119 | 120 | while (keep_processing): 121 | 122 | # if video file or camera successfully open then read frame from video 123 | 124 | if (cap.isOpened): 125 | ret, frame = cap.read() 126 | 127 | # when we reach the end of the video (file) exit cleanly 128 | 129 | if (ret == 0): 130 | keep_processing = False 131 | continue 132 | 133 | # rescale if specified 134 | 135 | if (args.rescale != 1.0): 136 | frame = cv2.resize( 137 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 138 | 139 | # get parameters from track bars 140 | 141 | gamma = cv2.getTrackbarPos("gamma, (* 0.01)", window_name2) * 0.01 142 | 143 | # make a copy 144 | 145 | gamma_img = frame.copy() 146 | 147 | # use power-law function to perform gamma correction 148 | 149 | gamma_img = powerlaw_transform(gamma_img, gamma) 150 | 151 | # display image 152 | 153 | cv2.imshow(window_name, frame) 154 | cv2.imshow(window_name2, gamma_img) 155 | 156 | # start the event loop - essential 157 | 158 | # cv2.waitKey() is a keyboard binding function (argument is the time in 159 | # ms). It waits for specified milliseconds for any keyboard event. 160 | # If you press any key in that time, the program continues. 161 | # If 0 is passed, it waits indefinitely for a key stroke. 162 | # (bitwise and with 0xFF to extract least significant byte of 163 | # multi-byte response) 164 | 165 | # wait 40ms (i.e. 1000ms / 25 fps = 40 ms) 166 | key = cv2.waitKey(40) & 0xFF 167 | 168 | # It can also be set to detect specific key strokes by recording which 169 | # key is pressed 170 | 171 | # e.g. if user presses "x" then exit 172 | 173 | if (key == ord('x')): 174 | keep_processing = False 175 | 176 | # close all windows 177 | 178 | cv2.destroyAllWindows() 179 | 180 | else: 181 | print("No usable camera connected.") 182 | 183 | 184 | ##################################################################### 185 | -------------------------------------------------------------------------------- /high_pass_filter.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : perform high pass filterings in fourier space of image frame 4 | # from a video file specified on the command line (e.g. python FILE.py 5 | # video_file) or from an attached web camera 6 | 7 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 8 | 9 | # Copyright (c) 2015 School of Engineering & Computing Science, 10 | # Copyright (c) 2019 Dept Computer Science, 11 | # Durham University, UK 12 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 13 | 14 | ##################################################################### 15 | 16 | import cv2 17 | import argparse 18 | import sys 19 | import numpy as np 20 | import math 21 | ##################################################################### 22 | 23 | # ignore divide by zero errors in np.log() operations 24 | 25 | np.seterr(divide='ignore') 26 | 27 | ##################################################################### 28 | 29 | keep_processing = True 30 | 31 | # parse command line arguments for camera ID or video file 32 | 33 | parser = argparse.ArgumentParser( 34 | description='Perform ' + 35 | sys.argv[0] + 36 | ' example operation on incoming camera/video image') 37 | parser.add_argument( 38 | "-c", 39 | "--camera_to_use", 40 | type=int, 41 | help="specify camera to use", 42 | default=0) 43 | parser.add_argument( 44 | "-r", 45 | "--rescale", 46 | type=float, 47 | help="rescale image by this factor", 48 | default=1.0) 49 | parser.add_argument( 50 | 'video_file', 51 | metavar='video_file', 52 | type=str, 53 | nargs='?', 54 | help='specify optional video file') 55 | args = parser.parse_args() 56 | 57 | 58 | ##################################################################### 59 | 60 | # create a simple high pass filter 61 | 62 | def create_high_pass_filter(width, height, radius): 63 | hp_filter = np.ones((height, width, 2), np.float32) 64 | cv2.circle(hp_filter, (int(width / 2), int(height / 2)), 65 | radius, (0, 0, 0), thickness=-1) 66 | return hp_filter 67 | 68 | 69 | ##################################################################### 70 | 71 | # this function is called as a call-back everytime the trackbar is moved 72 | # (here we just do nothing) 73 | 74 | 75 | def nothing(x): 76 | pass 77 | 78 | 79 | ##################################################################### 80 | 81 | # define video capture object 82 | 83 | try: 84 | # to use a non-buffered camera stream (via a separate thread) 85 | 86 | if not (args.video_file): 87 | import camera_stream 88 | cap = camera_stream.CameraVideoStream(use_tapi=False) 89 | else: 90 | cap = cv2.VideoCapture() # not needed for video files 91 | 92 | except BaseException: 93 | # if not then just use OpenCV default 94 | 95 | print("INFO: camera_stream class not found - camera input may be buffered") 96 | cap = cv2.VideoCapture() 97 | 98 | # define display window name 99 | 100 | window_name = "Live Camera Input" # window name 101 | window_name2 = "Fourier Magnitude Spectrum" # window name 102 | window_name3 = "Filtered Image" # window name 103 | 104 | # if command line arguments are provided try to read video_file 105 | # otherwise default to capture from attached H/W camera 106 | 107 | if (((args.video_file) and (cap.open(str(args.video_file)))) 108 | or (cap.open(args.camera_to_use))): 109 | 110 | # create windows by name (as resizable) 111 | 112 | cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) 113 | cv2.namedWindow(window_name2, cv2.WINDOW_NORMAL) 114 | cv2.namedWindow(window_name3, cv2.WINDOW_NORMAL) 115 | 116 | # add some track bar controllers for settings 117 | 118 | radius = 25 119 | cv2.createTrackbar("radius", window_name2, radius, 200, nothing) 120 | 121 | # if video file or camera successfully open then read frame from video 122 | 123 | if (cap.isOpened): 124 | ret, frame = cap.read() 125 | 126 | # rescale if specified 127 | 128 | if (args.rescale != 1.0): 129 | frame = cv2.resize(frame, (0, 0), fx=args.rescale, fy=args.rescale) 130 | 131 | # convert to grayscale 132 | 133 | gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 134 | 135 | # use this single frame to set up optimized DFT settings 136 | 137 | hieght, width = gray_frame.shape 138 | nheight = cv2.getOptimalDFTSize(hieght) 139 | nwidth = cv2.getOptimalDFTSize(width) 140 | 141 | while (keep_processing): 142 | 143 | # if video file or camera successfully open then read frame from video 144 | 145 | if (cap.isOpened): 146 | ret, frame = cap.read() 147 | 148 | # when we reach the end of the video (file) exit cleanly 149 | 150 | if (ret == 0): 151 | keep_processing = False 152 | continue 153 | 154 | # rescale if specified 155 | 156 | if (args.rescale != 1.0): 157 | frame = cv2.resize( 158 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 159 | 160 | # start a timer (to see how long processing and display takes) 161 | 162 | start_t = cv2.getTickCount() 163 | 164 | # convert to grayscale 165 | 166 | gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 167 | 168 | # Performance of DFT calculation, via the FFT, is better for array 169 | # sizes of power of two. Arrays whose size is a product of 170 | # 2's, 3's, and 5's are also processed quite efficiently. 171 | # Hence we modify the size of the array to the optimal size (by padding 172 | # zeros) before finding DFT. 173 | 174 | pad_right = nwidth - width 175 | pad_bottom = nheight - hieght 176 | nframe = cv2.copyMakeBorder( 177 | gray_frame, 178 | 0, 179 | pad_bottom, 180 | 0, 181 | pad_right, 182 | cv2.BORDER_CONSTANT, 183 | value=0) 184 | 185 | # perform the DFT and get complex output 186 | 187 | dft = cv2.dft(np.float32(nframe), flags=cv2.DFT_COMPLEX_OUTPUT) 188 | 189 | # shift it so that we the zero-frequency, F(0,0), DC component to the 190 | # center of the spectrum. 191 | 192 | dft_shifted = np.fft.fftshift(dft) 193 | 194 | # perform high pass filtering 195 | 196 | radius = cv2.getTrackbarPos("radius", window_name2) 197 | hp_filter = create_high_pass_filter(nwidth, nheight, radius) 198 | 199 | dft_filtered = cv2.mulSpectrums(dft_shifted, hp_filter, flags=0) 200 | 201 | # shift it back to original quaderant ordering 202 | 203 | dft = np.fft.fftshift(dft_filtered) 204 | 205 | # recover the original image via the inverse DFT 206 | 207 | filtered_img = cv2.dft(dft, flags=cv2.DFT_INVERSE) 208 | 209 | # normalized the filtered image into 0 -> 255 (8-bit grayscale) so we 210 | # can see the output 211 | 212 | min_val, max_val, min_loc, max_loc = \ 213 | cv2.minMaxLoc(filtered_img[:, :, 0]) 214 | filtered_img_normalized = filtered_img[:, :, 0] * ( 215 | 1.0 / (max_val - min_val)) + ((-min_val) / (max_val - min_val)) 216 | filtered_img_normalized = np.uint8(filtered_img_normalized * 255) 217 | 218 | # calculate the magnitude spectrum and log transform + scale it for 219 | # visualization 220 | 221 | magnitude_spectrum = np.log(cv2.magnitude( 222 | dft_filtered[:, :, 0], dft_filtered[:, :, 1])) 223 | 224 | # create a 8-bit image to put the magnitude spectrum into 225 | 226 | magnitude_spectrum_normalized = np.zeros( 227 | (nheight, nwidth, 1), np.uint8) 228 | 229 | # normalized the magnitude spectrum into 0 -> 255 (8-bit grayscale) so 230 | # we can see the output 231 | 232 | cv2.normalize( 233 | np.uint8(magnitude_spectrum), 234 | magnitude_spectrum_normalized, 235 | alpha=0, 236 | beta=255, 237 | norm_type=cv2.NORM_MINMAX) 238 | 239 | # display images 240 | 241 | cv2.imshow(window_name, gray_frame) 242 | cv2.imshow(window_name2, magnitude_spectrum_normalized) 243 | cv2.imshow(window_name3, filtered_img_normalized) 244 | 245 | # stop timer and convert to ms. (to see how long processing and display 246 | # takes) 247 | 248 | stop_t = ((cv2.getTickCount() - start_t) / 249 | cv2.getTickFrequency()) * 1000 250 | 251 | # start the event loop - essential 252 | 253 | # cv2.waitKey() is a keyboard binding function (argument is the time in 254 | # ms). It waits for specified milliseconds for any keyboard event. 255 | # If you press any key in that time, the program continues. 256 | # If 0 is passed, it waits indefinitely for a key stroke. 257 | # (bitwise and with 0xFF to extract least significant byte of 258 | # multi-byte response) 259 | 260 | # here we use a wait time in ms. that takes account of processing time 261 | # already used in the loop 262 | 263 | # wait 40ms (i.e. 1000ms / 25 fps = 40 ms) 264 | key = cv2.waitKey(max(2, 40 - int(math.ceil(stop_t)))) & 0xFF 265 | 266 | # It can also be set to detect specific key strokes by recording which 267 | # key is pressed 268 | 269 | # e.g. if user presses "x" then exit 270 | 271 | if (key == ord('x')): 272 | keep_processing = False 273 | 274 | # close all windows 275 | 276 | cv2.destroyAllWindows() 277 | 278 | else: 279 | print("No video file specified or camera connected.") 280 | 281 | ##################################################################### 282 | -------------------------------------------------------------------------------- /histogram.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : calculate and display the grayscale histogram from a video file 4 | # specified on the command line (e.g. python FILE.py video_file) or from an 5 | # attached web camera 6 | 7 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 8 | 9 | # Copyright (c) 2015 School of Engineering & Computing Science, 10 | # Copyright (c) 2019 Dept Computer Science, 11 | # Durham University, UK 12 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 13 | 14 | ##################################################################### 15 | 16 | import cv2 17 | import argparse 18 | import numpy as np 19 | import sys 20 | 21 | ##################################################################### 22 | 23 | keep_processing = True 24 | 25 | # parse command line arguments for camera ID or video file 26 | 27 | parser = argparse.ArgumentParser( 28 | description='Perform ' + 29 | sys.argv[0] + 30 | ' example operation on incoming camera/video image') 31 | parser.add_argument( 32 | "-c", 33 | "--camera_to_use", 34 | type=int, 35 | help="specify camera to use", 36 | default=0) 37 | parser.add_argument( 38 | "-r", 39 | "--rescale", 40 | type=float, 41 | help="rescale image by this factor", 42 | default=1.0) 43 | parser.add_argument( 44 | 'video_file', 45 | metavar='video_file', 46 | type=str, 47 | nargs='?', 48 | help='specify optional video file') 49 | args = parser.parse_args() 50 | 51 | 52 | ##################################################################### 53 | 54 | # basic grayscale histogram drawing in raw OpenCV using either a curve or lines 55 | 56 | # adapted from: 57 | # https://raw.githubusercontent.com/Itseez/opencv/master/samples/python2/hist.py 58 | 59 | def hist_curve(hist): 60 | h = np.ones((300, 256, 3)) * 255 # white background 61 | bins = np.arange(256).reshape(256, 1) 62 | cv2.normalize(hist, hist, 0, 255, cv2.NORM_MINMAX) 63 | hist = np.int32(np.around(hist)) 64 | pts = np.int32(np.column_stack((bins, hist))) 65 | cv2.polylines(h, [pts], False, (0, 0, 0)) # black line 66 | y = np.flipud(h) 67 | return y 68 | 69 | 70 | def hist_lines(hist): 71 | h = np.ones((300, 256, 3)) * 255 # white background 72 | cv2.normalize(hist, hist, 0, 255, cv2.NORM_MINMAX) 73 | hist = np.int32(np.around(hist)) 74 | for x, y in enumerate(hist): 75 | y = y[0] 76 | cv2.line(h, (x, 0), (x, y), (0, 0, 0)) # black bars 77 | y = np.flipud(h) 78 | return y 79 | 80 | 81 | ##################################################################### 82 | 83 | # define video capture object 84 | 85 | try: 86 | # to use a non-buffered camera stream (via a separate thread) 87 | 88 | if not (args.video_file): 89 | import camera_stream 90 | cap = camera_stream.CameraVideoStream(use_tapi=False) 91 | else: 92 | cap = cv2.VideoCapture() # not needed for video files 93 | 94 | except BaseException: 95 | # if not then just use OpenCV default 96 | 97 | print("INFO: camera_stream class not found - camera input may be buffered") 98 | cap = cv2.VideoCapture() 99 | 100 | # define display window name 101 | 102 | window_name = "Live Camera Input (as Greyscale)" # window name 103 | window_name2 = "Histogram (bar graph)" # window name 104 | window_name3 = "Histogram (line graph)" # window name 105 | 106 | 107 | # if command line arguments are provided try to read video_file 108 | # otherwise default to capture from attached H/W camera 109 | 110 | if (((args.video_file) and (cap.open(str(args.video_file)))) 111 | or (cap.open(args.camera_to_use))): 112 | 113 | # create window by name (as resizable) 114 | 115 | cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) 116 | cv2.namedWindow(window_name2, cv2.WINDOW_NORMAL) 117 | cv2.namedWindow(window_name3, cv2.WINDOW_NORMAL) 118 | 119 | while (keep_processing): 120 | 121 | # if video file or camera successfully open then read frame from video 122 | 123 | if (cap.isOpened): 124 | ret, frame = cap.read() 125 | 126 | # when we reach the end of the video (file) exit cleanly 127 | 128 | if (ret == 0): 129 | keep_processing = False 130 | continue 131 | 132 | # rescale if specified 133 | 134 | if (args.rescale != 1.0): 135 | frame = cv2.resize( 136 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 137 | 138 | # convert to grayscale 139 | 140 | gray_img = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 141 | 142 | # calculate the histogram over the whole image, for 1 channel 143 | # with one bin (histogram entry) for each value in the range 0 -> 255 144 | 145 | hist = cv2.calcHist([gray_img], [0], None, [256], [0, 256]) 146 | 147 | # draw the histogram distribution as an image 148 | # in two different visual forms (same info.) 149 | 150 | hist_img = hist_lines(hist) 151 | hist_img2 = hist_curve(hist) 152 | 153 | # display images 154 | 155 | cv2.imshow(window_name, gray_img) 156 | cv2.imshow(window_name2, hist_img) 157 | cv2.imshow(window_name3, hist_img2) 158 | 159 | # start the event loop - essential 160 | 161 | # cv2.waitKey() is a keyboard binding function (argument is the time in 162 | # ms). It waits for specified milliseconds for any keyboard event. 163 | # If you press any key in that time, the program continues. 164 | # If 0 is passed, it waits indefinitely for a key stroke. 165 | # (bitwise and with 0xFF to extract least significant byte of 166 | # multi-byte response) 167 | 168 | # wait 40ms (i.e. 1000ms / 25 fps = 40 ms) 169 | key = cv2.waitKey(40) & 0xFF 170 | 171 | # It can also be set to detect specific key strokes by recording which 172 | # key is pressed 173 | 174 | # e.g. if user presses "x" then exit 175 | 176 | if (key == ord('x')): 177 | keep_processing = False 178 | 179 | # close all windows 180 | 181 | cv2.destroyAllWindows() 182 | 183 | else: 184 | print("No video file specified or camera connected.") 185 | 186 | ##################################################################### 187 | -------------------------------------------------------------------------------- /histogram_equalize.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : histogram equalization from a video file 4 | # specified on the command line (e.g. python FILE.py video_file) or from an 5 | # attached web camera 6 | 7 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 8 | 9 | # Copyright (c) 2015 School of Engineering & Computing Science, 10 | # Copyright (c) 2019 Dept Computer Science, 11 | # Durham University, UK 12 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 13 | 14 | ##################################################################### 15 | 16 | import cv2 17 | import argparse 18 | import numpy as np 19 | import sys 20 | 21 | ##################################################################### 22 | 23 | keep_processing = True 24 | 25 | # parse command line arguments for camera ID or video file 26 | 27 | parser = argparse.ArgumentParser( 28 | description='Perform ' + 29 | sys.argv[0] + 30 | ' example operation on incoming camera/video image') 31 | parser.add_argument( 32 | "-c", 33 | "--camera_to_use", 34 | type=int, 35 | help="specify camera to use", 36 | default=0) 37 | parser.add_argument( 38 | "-r", 39 | "--rescale", 40 | type=float, 41 | help="rescale image by this factor", 42 | default=1.0) 43 | parser.add_argument( 44 | 'video_file', 45 | metavar='video_file', 46 | type=str, 47 | nargs='?', 48 | help='specify optional video file') 49 | args = parser.parse_args() 50 | 51 | 52 | ##################################################################### 53 | 54 | # basic grayscale histogram drawing in raw OpenCV using lines 55 | 56 | # adapted from: 57 | # https://raw.githubusercontent.com/Itseez/opencv/master/samples/python2/hist.py 58 | 59 | def hist_lines(hist): 60 | h = np.ones((300, 256, 3)) * 255 # white background 61 | cv2.normalize(hist, hist, 0, 255, cv2.NORM_MINMAX) 62 | hist = np.int32(np.around(hist)) 63 | for x, y in enumerate(hist): 64 | y = y[0] 65 | cv2.line(h, (x, 0), (x, y), (0, 0, 0)) # black bars 66 | y = np.flipud(h) 67 | return y 68 | 69 | 70 | ##################################################################### 71 | 72 | # define video capture object 73 | 74 | try: 75 | # to use a non-buffered camera stream (via a separate thread) 76 | 77 | if not (args.video_file): 78 | import camera_stream 79 | cap = camera_stream.CameraVideoStream(use_tapi=False) 80 | else: 81 | cap = cv2.VideoCapture() # not needed for video files 82 | 83 | except BaseException: 84 | # if not then just use OpenCV default 85 | 86 | print("INFO: camera_stream class not found - camera input may be buffered") 87 | cap = cv2.VideoCapture() 88 | 89 | # define display window name 90 | 91 | window_name1 = "Live Camera Input" # window name 92 | window_name2 = "Input Histogram" # window name 93 | window_name3 = "Processed Output" # window name 94 | window_name4 = "Output Histogram" # window name 95 | 96 | # if command line arguments are provided try to read video_file 97 | # otherwise default to capture from attached H/W camera 98 | 99 | if (((args.video_file) and (cap.open(str(args.video_file)))) 100 | or (cap.open(args.camera_to_use))): 101 | 102 | # create window by name (as resizable) 103 | 104 | cv2.namedWindow(window_name1, cv2.WINDOW_NORMAL) 105 | cv2.namedWindow(window_name2, cv2.WINDOW_NORMAL) 106 | cv2.namedWindow(window_name3, cv2.WINDOW_NORMAL) 107 | cv2.namedWindow(window_name4, cv2.WINDOW_NORMAL) 108 | 109 | while (keep_processing): 110 | 111 | # if video file or camera successfully open then read frame from video 112 | 113 | if (cap.isOpened): 114 | ret, frame = cap.read() 115 | 116 | # when we reach the end of the video (file) exit cleanly 117 | 118 | if (ret == 0): 119 | keep_processing = False 120 | continue 121 | 122 | # rescale if specified 123 | 124 | if (args.rescale != 1.0): 125 | frame = cv2.resize( 126 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 127 | 128 | # convert to grayscale 129 | 130 | gray_img = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 131 | 132 | # perform histogram equalization 133 | 134 | output = cv2.equalizeHist(gray_img) 135 | 136 | # display image 137 | 138 | cv2.imshow(window_name1, gray_img) 139 | cv2.imshow( 140 | window_name2, hist_lines( 141 | cv2.calcHist( 142 | [gray_img], [0], None, [256], [ 143 | 0, 256]))) 144 | cv2.imshow(window_name3, output) 145 | cv2.imshow( 146 | window_name4, hist_lines( 147 | cv2.calcHist( 148 | [output], [0], None, [256], [ 149 | 0, 256]))) 150 | 151 | # start the event loop - essential 152 | 153 | # cv2.waitKey() is a keyboard binding function (argument is the time in 154 | # ms). It waits for specified milliseconds for any keyboard event. 155 | # If you press any key in that time, the program continues. 156 | # If 0 is passed, it waits indefinitely for a key stroke. 157 | # (bitwise and with 0xFF to extract least significant byte of 158 | # multi-byte response) 159 | 160 | # wait 40ms (i.e. 1000ms / 25 fps = 40 ms) 161 | key = cv2.waitKey(40) & 0xFF 162 | 163 | # It can also be set to detect specific key strokes by recording which 164 | # key is pressed 165 | 166 | # e.g. if user presses "x" then exit 167 | 168 | if (key == ord('x')): 169 | keep_processing = False 170 | 171 | # close all windows 172 | 173 | cv2.destroyAllWindows() 174 | 175 | else: 176 | print("No video file specified or camera connected.") 177 | 178 | ##################################################################### 179 | -------------------------------------------------------------------------------- /hsv_viewer.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : display individual HSV channels from an video file 4 | # specified on the command line (e.g. python FILE.py video_file) or from an 5 | # attached web camera 6 | 7 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 8 | 9 | # Copyright (c) 2015 School of Engineering & Computing Science, 10 | # Copyright (c) 2019 Dept Computer Science, 11 | # Durham University, UK 12 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 13 | 14 | ##################################################################### 15 | 16 | import cv2 17 | import argparse 18 | import sys 19 | import numpy as np 20 | import math 21 | 22 | ##################################################################### 23 | 24 | keep_processing = True 25 | 26 | # parse command line arguments for camera ID or video file 27 | 28 | parser = argparse.ArgumentParser( 29 | description='Perform ' + 30 | sys.argv[0] + 31 | ' example operation on incoming camera/video image') 32 | parser.add_argument( 33 | "-c", 34 | "--camera_to_use", 35 | type=int, 36 | help="specify camera to use", 37 | default=0) 38 | parser.add_argument( 39 | "-r", 40 | "--rescale", 41 | type=float, 42 | help="rescale image by this factor", 43 | default=1.0) 44 | parser.add_argument( 45 | 'video_file', 46 | metavar='video_file', 47 | type=str, 48 | nargs='?', 49 | help='specify optional video file') 50 | args = parser.parse_args() 51 | 52 | 53 | colour_map_hue = False # use colour mapping to display Hue 54 | 55 | ##################################################################### 56 | 57 | # define video capture object 58 | 59 | try: 60 | # to use a non-buffered camera stream (via a separate thread) 61 | 62 | if not (args.video_file): 63 | import camera_stream 64 | cap = camera_stream.CameraVideoStream(use_tapi=False) 65 | else: 66 | cap = cv2.VideoCapture() # not needed for video files 67 | 68 | except BaseException: 69 | # if not then just use OpenCV default 70 | 71 | print("INFO: camera_stream class not found - camera input may be buffered") 72 | cap = cv2.VideoCapture() 73 | 74 | # define display window name 75 | 76 | window_name = "Live Camera Input" # window name 77 | window_name_hue = "Hue Channel" # window name 78 | window_name_sat = "Saturation Channel" # window name 79 | window_name_val = "Value Channel" # window name 80 | 81 | # if command line arguments are provided try to read video_file 82 | # otherwise default to capture from attached H/W camera 83 | 84 | if (((args.video_file) and (cap.open(str(args.video_file)))) 85 | or (cap.open(args.camera_to_use))): 86 | 87 | # create window by name (note flags for resizable or not) 88 | 89 | cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) 90 | 91 | # usage 92 | 93 | print("USAGE: press 'c' to toggle Hue channel colour mapping") 94 | 95 | while (keep_processing): 96 | 97 | # if video file or camera successfully open then read frame from video 98 | 99 | if (cap.isOpened): 100 | ret, frame = cap.read() 101 | 102 | # when we reach the end of the video (file) exit cleanly 103 | 104 | if (ret == 0): 105 | keep_processing = False 106 | continue 107 | 108 | # rescale if specified 109 | 110 | if (args.rescale != 1.0): 111 | frame = cv2.resize( 112 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 113 | 114 | # start a timer (to see how long processing and display takes) 115 | 116 | start_t = cv2.getTickCount() 117 | 118 | img_hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) 119 | 120 | # display images 121 | 122 | cv2.imshow(window_name, frame) 123 | 124 | # colour channels are HSV ordering in OpenCV 125 | 126 | cv2.imshow(window_name_sat, img_hsv[:, :, 1]) # saturation 127 | cv2.imshow(window_name_val, img_hsv[:, :, 2]) # value 128 | 129 | if (colour_map_hue): 130 | # re map S and V to top outer rim of HSV colour space 131 | 132 | img_hsv[:, :, 1] = np.ones(img_hsv[:, :, 1].shape) * 255 133 | img_hsv[:, :, 2] = np.ones(img_hsv[:, :, 1].shape) * 255 134 | 135 | # convert the result back to BGR to produce a false colour 136 | # version of hue for display 137 | 138 | colour_mapped_hue = cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR) 139 | cv2.imshow(window_name_hue, colour_mapped_hue) # colour mapped hue 140 | else: 141 | cv2.imshow(window_name_hue, img_hsv[:, :, 0]) # hue 142 | 143 | # stop the timer and convert to ms. (to see how long processing and 144 | # display takes) 145 | 146 | stop_t = ((cv2.getTickCount() - start_t) / 147 | cv2.getTickFrequency()) * 1000 148 | 149 | # start the event loop - essential 150 | 151 | # cv2.waitKey() is a keyboard binding function (argument is the time in 152 | # ms). It waits for specified milliseconds for any keyboard event. 153 | # If you press any key in that time, the program continues. 154 | # If 0 is passed, it waits indefinitely for a key stroke. 155 | # (bitwise and with 0xFF to extract least significant byte of 156 | # multi-byte response) 157 | 158 | # wait 40ms or less depending on processing time taken (i.e. 1000ms / 159 | # 25 fps = 40 ms) 160 | 161 | key = cv2.waitKey(max(2, 40 - int(math.ceil(stop_t)))) & 0xFF 162 | 163 | # It can also be set to detect specific key strokes by recording which 164 | # key is pressed 165 | 166 | # e.g. if user presses "x" then exit 167 | 168 | if (key == ord('x')): 169 | keep_processing = False 170 | elif (key == ord('c')): 171 | colour_map_hue = not (colour_map_hue) 172 | 173 | # close all windows 174 | 175 | cv2.destroyAllWindows() 176 | 177 | else: 178 | print("No video file specified or camera connected.") 179 | 180 | ##################################################################### 181 | -------------------------------------------------------------------------------- /jpeg_compression_noise.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : JPEG compression as processing on frames from a video file 4 | # specified on the command line (e.g. python FILE.py video_file) or from an 5 | # attached web camera 6 | 7 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 8 | 9 | # Copyright (c) 2015 School of Engineering & Computing Science, 10 | # Copyright (c) 2019 Dept Computer Science, 11 | # Durham University, UK 12 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 13 | 14 | ##################################################################### 15 | 16 | import cv2 17 | import argparse 18 | import sys 19 | import math 20 | 21 | ##################################################################### 22 | 23 | keep_processing = True 24 | 25 | # parse command line arguments for camera ID or video file 26 | 27 | parser = argparse.ArgumentParser( 28 | description='Perform ' + 29 | sys.argv[0] + 30 | ' example operation on incoming camera/video image') 31 | parser.add_argument( 32 | "-c", 33 | "--camera_to_use", 34 | type=int, 35 | help="specify camera to use", 36 | default=0) 37 | parser.add_argument( 38 | "-r", 39 | "--rescale", 40 | type=float, 41 | help="rescale image by this factor", 42 | default=1.0) 43 | parser.add_argument( 44 | 'video_file', 45 | metavar='video_file', 46 | type=str, 47 | nargs='?', 48 | help='specify optional video file') 49 | args = parser.parse_args() 50 | 51 | 52 | ##################################################################### 53 | 54 | # this function is called as a call-back everytime the trackbar is moved 55 | # (here we just do nothing) 56 | 57 | 58 | def nothing(x): 59 | pass 60 | 61 | 62 | ##################################################################### 63 | 64 | # define video capture object 65 | 66 | try: 67 | # to use a non-buffered camera stream (via a separate thread) 68 | 69 | if not (args.video_file): 70 | import camera_stream 71 | cap = camera_stream.CameraVideoStream(use_tapi=False) 72 | else: 73 | cap = cv2.VideoCapture() # not needed for video files 74 | 75 | except BaseException: 76 | # if not then just use OpenCV default 77 | 78 | print("INFO: camera_stream class not found - camera input may be buffered") 79 | cap = cv2.VideoCapture() 80 | 81 | # define display window name 82 | 83 | window_name = "Live Camera Input" # window name 84 | window_name2 = "JPEG compression noise" # window name 85 | window_name_jpeg = "JPEG compressed version" # window name 86 | 87 | # if command line arguments are provided try to read video_file 88 | # otherwise default to capture from attached H/W camera 89 | 90 | if (((args.video_file) and (cap.open(str(args.video_file)))) 91 | or (cap.open(args.camera_to_use))): 92 | 93 | # create window by name (note flags for resizable or not) 94 | 95 | cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) 96 | cv2.namedWindow(window_name2, cv2.WINDOW_NORMAL) 97 | cv2.namedWindow(window_name_jpeg, cv2.WINDOW_NORMAL) 98 | 99 | jpeg_quality = 90 100 | cv2.createTrackbar("JPEG quality", 101 | window_name2, jpeg_quality, 100, nothing) 102 | 103 | amplification = 0 104 | cv2.createTrackbar( 105 | "amplification", 106 | window_name2, 107 | amplification, 108 | 255, 109 | nothing) 110 | 111 | while (keep_processing): 112 | 113 | # if video file or camera successfully open then read frame from video 114 | 115 | if (cap.isOpened): 116 | ret, frame = cap.read() 117 | 118 | # when we reach the end of the video (file) exit cleanly 119 | 120 | if (ret == 0): 121 | keep_processing = False 122 | continue 123 | 124 | # rescale if specified 125 | 126 | if (args.rescale != 1.0): 127 | frame = cv2.resize( 128 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 129 | 130 | # start a timer (to see how long processing and display takes) 131 | 132 | start_t = cv2.getTickCount() 133 | 134 | # write/compress and then read back from as JPEG 135 | 136 | jpeg_quality = cv2.getTrackbarPos("JPEG quality", window_name2) 137 | encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), jpeg_quality] 138 | 139 | # either via file output / input 140 | 141 | # cv2.imwrite("camera.jpg", frame, encode_param) 142 | # jpeg_img = cv2.imread("camera.jpg") 143 | 144 | # or via encoding / decoding in a memory buffer 145 | 146 | retval, buffer = cv2.imencode(".JPG", frame, encode_param) 147 | jpeg_img = cv2.imdecode(buffer, flags=cv2.IMREAD_COLOR) 148 | 149 | # compute absolute difference between original and compressed version 150 | 151 | diff_img = cv2.absdiff(jpeg_img, frame) 152 | 153 | # retrieve the amplification setting from the track bar 154 | 155 | amplification = cv2.getTrackbarPos("amplification", window_name2) 156 | 157 | # multiple the result to increase the amplification (so we can see 158 | # small pixel changes) 159 | 160 | amplified_diff_img = diff_img * amplification 161 | 162 | # display images 163 | 164 | cv2.imshow(window_name, frame) 165 | cv2.imshow(window_name2, amplified_diff_img) 166 | cv2.imshow(window_name_jpeg, jpeg_img) 167 | 168 | # stop the timer and convert to ms. (to see how long processing and 169 | # display takes) 170 | 171 | stop_t = ((cv2.getTickCount() - start_t) / 172 | cv2.getTickFrequency()) * 1000 173 | 174 | # start the event loop - essential 175 | 176 | # cv2.waitKey() is a keyboard binding function (argument is the time in 177 | # ms). It waits for specified milliseconds for any keyboard event. 178 | # If you press any key in that time, the program continues. 179 | # If 0 is passed, it waits indefinitely for a key stroke. 180 | # (bitwise and with 0xFF to extract least significant byte of 181 | # multi-byte response) 182 | 183 | # wait 40ms or less depending on processing time taken (i.e. 1000ms / 184 | # 25 fps = 40 ms) 185 | 186 | key = cv2.waitKey(max(2, 40 - int(math.ceil(stop_t)))) & 0xFF 187 | 188 | # It can also be set to detect specific key strokes by recording which 189 | # key is pressed 190 | 191 | # e.g. if user presses "x" then exit 192 | 193 | if (key == ord('x')): 194 | keep_processing = False 195 | 196 | # close all windows 197 | 198 | cv2.destroyAllWindows() 199 | 200 | else: 201 | print("No video file specified or camera connected.") 202 | 203 | ##################################################################### 204 | -------------------------------------------------------------------------------- /logarithmic.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : logarithmic transform on an image from an attached web camera 4 | 5 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 6 | 7 | # Copyright (c) 2015 School of Engineering & Computing Science, 8 | # Copyright (c) 2019 Dept Computer Science, 9 | # Durham University, UK 10 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 11 | 12 | ##################################################################### 13 | 14 | import cv2 15 | import sys 16 | import argparse 17 | import math 18 | 19 | ##################################################################### 20 | 21 | keep_processing = True 22 | 23 | # parse command line arguments for camera ID or video file 24 | 25 | parser = argparse.ArgumentParser( 26 | description='Perform ' + 27 | sys.argv[0] + 28 | ' example operation on incoming camera/video image') 29 | parser.add_argument( 30 | "-c", 31 | "--camera_to_use", 32 | type=int, 33 | help="specify camera to use", 34 | default=0) 35 | parser.add_argument( 36 | "-r", 37 | "--rescale", 38 | type=float, 39 | help="rescale image by this factor", 40 | default=1.0) 41 | parser.add_argument( 42 | 'video_file', 43 | metavar='video_file', 44 | type=str, 45 | nargs='?', 46 | help='specify optional video file') 47 | args = parser.parse_args() 48 | 49 | 50 | ##################################################################### 51 | 52 | # this function is called as a call-back everytime the trackbar is moved 53 | # (here we just do nothing) 54 | 55 | def nothing(x): 56 | pass 57 | 58 | 59 | ##################################################################### 60 | 61 | # logarithmic transform 62 | # image - greyscale image 63 | # c - scaling constant 64 | # sigma - "gradient" co-efficient of logarithmic function 65 | 66 | 67 | def logarithmic_transform(image, c, sigma): 68 | for i in range(0, image.shape[1]): # image width 69 | for j in range(0, image.shape[0]): # image height 70 | 71 | # compute logarithmic transform 72 | 73 | image[j, i] = int(c * math.log(1 + 74 | ((math.exp(sigma) - 1) * image[j, i]))) 75 | 76 | return image 77 | 78 | 79 | ##################################################################### 80 | 81 | # define video capture object 82 | 83 | try: 84 | # to use a non-buffered camera stream (via a separate thread) 85 | 86 | if not (args.video_file): 87 | import camera_stream 88 | cap = camera_stream.CameraVideoStream(use_tapi=False) 89 | else: 90 | cap = cv2.VideoCapture() # not needed for video files 91 | 92 | except BaseException: 93 | # if not then just use OpenCV default 94 | 95 | print("INFO: camera_stream class not found - camera input may be buffered") 96 | cap = cv2.VideoCapture() 97 | 98 | # define display window name 99 | 100 | window_name = "Live Camera Input" # window name 101 | window_name2 = "Logarithmic Transform" # window name 102 | 103 | # if command line arguments are provided try to read video_file 104 | # otherwise default to capture from attached H/W camera 105 | 106 | if (((args.video_file) and (cap.open(str(args.video_file)))) 107 | or (cap.open(args.camera_to_use))): 108 | 109 | # create window by name (as resizable) 110 | 111 | cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) 112 | cv2.namedWindow(window_name2, cv2.WINDOW_NORMAL) 113 | 114 | # add some track bar controllers for settings 115 | 116 | constant = 10 117 | cv2.createTrackbar("constant, C", window_name2, constant, 100, nothing) 118 | 119 | sigma = 1 120 | cv2.createTrackbar("sigma (*0.01)", window_name2, sigma, 10, nothing) 121 | 122 | while (keep_processing): 123 | 124 | # if video file or camera successfully open then read frame from video 125 | 126 | if (cap.isOpened): 127 | ret, frame = cap.read() 128 | 129 | # when we reach the end of the video (file) exit cleanly 130 | 131 | if (ret == 0): 132 | keep_processing = False 133 | continue 134 | 135 | # rescale if specified 136 | 137 | if (args.rescale != 1.0): 138 | frame = cv2.resize( 139 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 140 | 141 | # convert to grayscale 142 | 143 | gray_img = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 144 | 145 | # get parameters from track bars 146 | 147 | constant = cv2.getTrackbarPos("constant, C", window_name2) 148 | sigma = cv2.getTrackbarPos("sigma (*0.01)", window_name2) * 0.01 149 | 150 | # make a copy and log tranform it 151 | 152 | log_img = gray_img.copy() 153 | log_img = logarithmic_transform(log_img, constant, sigma) 154 | 155 | # display image 156 | 157 | cv2.imshow(window_name, gray_img) 158 | cv2.imshow(window_name2, log_img) 159 | 160 | # start the event loop - essential 161 | 162 | # cv2.waitKey() is a keyboard binding function (argument is the time in 163 | # ms). It waits for specified milliseconds for any keyboard event. 164 | # If you press any key in that time, the program continues. 165 | # If 0 is passed, it waits indefinitely for a key stroke. 166 | # (bitwise and with 0xFF to extract least significant byte of 167 | # multi-byte response) 168 | 169 | # wait 40ms (i.e. 1000ms / 25 fps = 40 ms) 170 | key = cv2.waitKey(40) & 0xFF 171 | 172 | # It can also be set to detect specific key strokes by recording which 173 | # key is pressed 174 | 175 | # e.g. if user presses "x" then exit 176 | 177 | if (key == ord('x')): 178 | keep_processing = False 179 | 180 | # close all windows 181 | 182 | cv2.destroyAllWindows() 183 | 184 | else: 185 | print("No usable camera connected.") 186 | 187 | 188 | ##################################################################### 189 | -------------------------------------------------------------------------------- /low_pass_filter.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : perform low pass filterings in fourier space of image frame 4 | # from a video file specified on the command line (e.g. python FILE.py 5 | # video_file) or from an attached web camera 6 | 7 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 8 | 9 | # Copyright (c) 2015 School of Engineering & Computing Science, 10 | # Copyright (c) 2019 Dept Computer Science, 11 | # Durham University, UK 12 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 13 | 14 | ##################################################################### 15 | 16 | import cv2 17 | import argparse 18 | import sys 19 | import numpy as np 20 | import math 21 | 22 | ##################################################################### 23 | 24 | # ignore divide by zero errors in np.log() operations 25 | 26 | np.seterr(divide='ignore') 27 | 28 | ##################################################################### 29 | 30 | keep_processing = True 31 | 32 | # parse command line arguments for camera ID or video file 33 | 34 | parser = argparse.ArgumentParser( 35 | description='Perform ' + 36 | sys.argv[0] + 37 | ' example operation on incoming camera/video image') 38 | parser.add_argument( 39 | "-c", 40 | "--camera_to_use", 41 | type=int, 42 | help="specify camera to use", 43 | default=0) 44 | parser.add_argument( 45 | "-r", 46 | "--rescale", 47 | type=float, 48 | help="rescale image by this factor", 49 | default=1.0) 50 | parser.add_argument( 51 | 'video_file', 52 | metavar='video_file', 53 | type=str, 54 | nargs='?', 55 | help='specify optional video file') 56 | args = parser.parse_args() 57 | 58 | ##################################################################### 59 | 60 | # create a simple low pass filter 61 | 62 | 63 | def create_low_pass_filter(width, height, radius): 64 | lp_filter = np.zeros((height, width, 2), np.float32) 65 | cv2.circle(lp_filter, (int(width / 2), int(height / 2)), 66 | radius, (1, 1, 1), thickness=-1) 67 | return lp_filter 68 | 69 | 70 | ##################################################################### 71 | 72 | # this function is called as a call-back everytime the trackbar is moved 73 | # (here we just do nothing) 74 | 75 | 76 | def nothing(x): 77 | pass 78 | 79 | 80 | ##################################################################### 81 | 82 | # define video capture object 83 | 84 | try: 85 | # to use a non-buffered camera stream (via a separate thread) 86 | 87 | if not (args.video_file): 88 | import camera_stream 89 | cap = camera_stream.CameraVideoStream(use_tapi=False) 90 | else: 91 | cap = cv2.VideoCapture() # not needed for video files 92 | 93 | except BaseException: 94 | # if not then just use OpenCV default 95 | 96 | print("INFO: camera_stream class not found - camera input may be buffered") 97 | cap = cv2.VideoCapture() 98 | 99 | # define display window name 100 | 101 | window_name = "Live Camera Input" # window name 102 | window_name2 = "Fourier Magnitude Spectrum" # window name 103 | window_name3 = "Filtered Image" # window name 104 | 105 | # if command line arguments are provided try to read video_file 106 | # otherwise default to capture from attached H/W camera 107 | 108 | if (((args.video_file) and (cap.open(str(args.video_file)))) 109 | or (cap.open(args.camera_to_use))): 110 | 111 | # create windows by name (as resizable) 112 | 113 | cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) 114 | cv2.namedWindow(window_name2, cv2.WINDOW_NORMAL) 115 | cv2.namedWindow(window_name3, cv2.WINDOW_NORMAL) 116 | 117 | # add some track bar controllers for settings 118 | 119 | radius = 25 120 | cv2.createTrackbar("radius", window_name2, radius, 400, nothing) 121 | 122 | # if video file or camera successfully open then read frame from video 123 | 124 | if (cap.isOpened): 125 | ret, frame = cap.read() 126 | 127 | # rescale if specified 128 | 129 | if (args.rescale != 1.0): 130 | frame = cv2.resize(frame, (0, 0), fx=args.rescale, fy=args.rescale) 131 | 132 | # convert to grayscale 133 | 134 | gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 135 | 136 | # use this single frame to set up optimized DFT settings 137 | 138 | height, width = gray_frame.shape 139 | nheight = cv2.getOptimalDFTSize(height) 140 | nwidth = cv2.getOptimalDFTSize(width) 141 | 142 | while (keep_processing): 143 | 144 | # if video file or camera successfully open then read frame from video 145 | 146 | if (cap.isOpened): 147 | ret, frame = cap.read() 148 | 149 | # when we reach the end of the video (file) exit cleanly 150 | 151 | if (ret == 0): 152 | keep_processing = False 153 | continue 154 | 155 | # rescale if specified 156 | 157 | if (args.rescale != 1.0): 158 | frame = cv2.resize( 159 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 160 | 161 | # start a timer (to see how long processing and display takes) 162 | 163 | start_t = cv2.getTickCount() 164 | 165 | # convert to grayscale 166 | 167 | gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 168 | 169 | # Performance of DFT calculation, via the FFT, is better for array 170 | # sizes of power of two. Arrays whose size is a product of 171 | # 2's, 3's, and 5's are also processed quite efficiently. 172 | # Hence we modify the size of the array to the optimal size (by padding 173 | # zeros) before finding DFT. 174 | 175 | pad_right = nwidth - width 176 | pad_bottom = nheight - height 177 | nframe = cv2.copyMakeBorder( 178 | gray_frame, 179 | 0, 180 | pad_bottom, 181 | 0, 182 | pad_right, 183 | cv2.BORDER_CONSTANT, 184 | value=0) 185 | 186 | # perform the DFT and get complex output 187 | 188 | dft = cv2.dft(np.float32(nframe), flags=cv2.DFT_COMPLEX_OUTPUT) 189 | 190 | # shift it so that we the zero-frequency, F(0,0), DC component to the 191 | # center of the spectrum. 192 | 193 | dft_shifted = np.fft.fftshift(dft) 194 | 195 | # perform low pass filtering 196 | 197 | radius = cv2.getTrackbarPos("radius", window_name2) 198 | hp_filter = create_low_pass_filter(nwidth, nheight, radius) 199 | 200 | dft_filtered = cv2.mulSpectrums(dft_shifted, hp_filter, flags=0) 201 | 202 | # shift it back to original quaderant ordering 203 | 204 | dft = np.fft.fftshift(dft_filtered) 205 | 206 | # recover the original image via the inverse DFT 207 | 208 | filtered_img = cv2.dft(dft, flags=cv2.DFT_INVERSE) 209 | 210 | # normalized the filtered image into 0 -> 255 (8-bit grayscale) so we 211 | # can see the output 212 | 213 | min_val, max_val, min_loc, max_loc = \ 214 | cv2.minMaxLoc(filtered_img[:, :, 0]) 215 | filtered_img_normalized = filtered_img[:, :, 0] * ( 216 | 1.0 / (max_val - min_val)) + ((-min_val) / (max_val - min_val)) 217 | filtered_img_normalized = np.uint8(filtered_img_normalized * 255) 218 | 219 | # calculate the magnitude spectrum and log transform + scale it for 220 | # visualization 221 | 222 | magnitude_spectrum = np.log(cv2.magnitude( 223 | dft_filtered[:, :, 0], dft_filtered[:, :, 1])) 224 | 225 | # create a 8-bit image to put the magnitude spectrum into 226 | 227 | magnitude_spectrum_normalized = np.zeros( 228 | (nheight, nwidth, 1), np.uint8) 229 | 230 | # normalized the magnitude spectrum into 0 -> 255 (8-bit grayscale) so 231 | # we can see the output 232 | 233 | cv2.normalize( 234 | np.uint8(magnitude_spectrum), 235 | magnitude_spectrum_normalized, 236 | alpha=0, 237 | beta=255, 238 | norm_type=cv2.NORM_MINMAX) 239 | 240 | # display images 241 | 242 | cv2.imshow(window_name, gray_frame) 243 | cv2.imshow(window_name2, magnitude_spectrum_normalized) 244 | cv2.imshow(window_name3, filtered_img_normalized) 245 | 246 | # stop timer and convert to ms. (to see how long processing and display 247 | # takes) 248 | 249 | stop_t = ((cv2.getTickCount() - start_t) / 250 | cv2.getTickFrequency()) * 1000 251 | 252 | # start the event loop - essential 253 | 254 | # cv2.waitKey() is a keyboard binding function (argument is the time in 255 | # ms). It waits for specified milliseconds for any keyboard event. 256 | # If you press any key in that time, the program continues. 257 | # If 0 is passed, it waits indefinitely for a key stroke. 258 | # (bitwise and with 0xFF to extract least significant byte of 259 | # multi-byte response) 260 | 261 | # here we use a wait time in ms. that takes account of processing time 262 | # already used in the loop 263 | 264 | # wait 40ms (i.e. 1000ms / 25 fps = 40 ms) 265 | key = cv2.waitKey(max(2, 40 - int(math.ceil(stop_t)))) & 0xFF 266 | 267 | # It can also be set to detect specific key strokes by recording which 268 | # key is pressed 269 | 270 | # e.g. if user presses "x" then exit 271 | 272 | if (key == ord('x')): 273 | keep_processing = False 274 | 275 | # close all windows 276 | 277 | cv2.destroyAllWindows() 278 | 279 | else: 280 | print("No video file specified or camera connected.") 281 | 282 | ##################################################################### 283 | -------------------------------------------------------------------------------- /mean_filter.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : mean filter on an image from an attached web camera 4 | 5 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 6 | 7 | # Copyright (c) 2015 School of Engineering & Computing Science, 8 | # Copyright (c) 2019 Dept Computer Science, 9 | # Durham University, UK 10 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 11 | 12 | ##################################################################### 13 | 14 | import cv2 15 | import sys 16 | import argparse 17 | 18 | ##################################################################### 19 | 20 | keep_processing = True 21 | 22 | # parse command line arguments for camera ID or video file 23 | 24 | parser = argparse.ArgumentParser( 25 | description='Perform ' + 26 | sys.argv[0] + 27 | ' example operation on incoming camera/video image') 28 | parser.add_argument( 29 | "-c", 30 | "--camera_to_use", 31 | type=int, 32 | help="specify camera to use", 33 | default=0) 34 | parser.add_argument( 35 | "-r", 36 | "--rescale", 37 | type=float, 38 | help="rescale image by this factor", 39 | default=1.0) 40 | parser.add_argument( 41 | 'video_file', 42 | metavar='video_file', 43 | type=str, 44 | nargs='?', 45 | help='specify optional video file') 46 | args = parser.parse_args() 47 | 48 | 49 | ##################################################################### 50 | 51 | # this function is called as a call-back everytime the trackbar is moved 52 | # (here we just do nothing) 53 | 54 | def nothing(x): 55 | pass 56 | 57 | 58 | ##################################################################### 59 | 60 | # define video capture object 61 | 62 | try: 63 | # to use a non-buffered camera stream (via a separate thread) 64 | 65 | if not (args.video_file): 66 | import camera_stream 67 | cap = camera_stream.CameraVideoStream(use_tapi=False) 68 | else: 69 | cap = cv2.VideoCapture() # not needed for video files 70 | 71 | except BaseException: 72 | # if not then just use OpenCV default 73 | 74 | print("INFO: camera_stream class not found - camera input may be buffered") 75 | cap = cv2.VideoCapture() 76 | 77 | # define display window name 78 | 79 | window_name = "Live Camera Input" # window name 80 | window_name2 = "Mean Filtering" # window name 81 | 82 | # if command line arguments are provided try to read video_file 83 | # otherwise default to capture from attached H/W camera 84 | 85 | if (((args.video_file) and (cap.open(str(args.video_file)))) 86 | or (cap.open(args.camera_to_use))): 87 | 88 | # create window by name 89 | 90 | cv2.namedWindow(window_name, cv2.WINDOW_AUTOSIZE) 91 | cv2.namedWindow(window_name2, cv2.WINDOW_AUTOSIZE) 92 | 93 | # add some track bar controllers for settings 94 | 95 | neighbourhood = 3 96 | cv2.createTrackbar( 97 | "neighbourhood, N", 98 | window_name2, 99 | neighbourhood, 100 | 25, 101 | nothing) 102 | 103 | while (keep_processing): 104 | 105 | # if video file or camera successfully open then read frame from video 106 | 107 | if (cap.isOpened): 108 | ret, frame = cap.read() 109 | 110 | # when we reach the end of the video (file) exit cleanly 111 | 112 | if (ret == 0): 113 | keep_processing = False 114 | continue 115 | 116 | # rescale if specified 117 | 118 | if (args.rescale != 1.0): 119 | frame = cv2.resize( 120 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 121 | 122 | # get parameters from track bars 123 | 124 | neighbourhood = cv2.getTrackbarPos("neighbourhood, N", window_name2) 125 | 126 | neighbourhood = max(3, neighbourhood) 127 | 128 | # in opencv blur() performs filtering with a NxN kernel where each 129 | # element has a weight of 1 / (N^2) - this is mean filtering 130 | 131 | mean_img = cv2.blur( 132 | frame, 133 | (neighbourhood, 134 | neighbourhood), 135 | borderType=cv2.BORDER_DEFAULT) 136 | 137 | # display image 138 | 139 | cv2.imshow(window_name, frame) 140 | cv2.imshow(window_name2, mean_img) 141 | 142 | # start the event loop - essential 143 | 144 | # cv2.waitKey() is a keyboard binding function (argument is the time in 145 | # ms). It waits for specified milliseconds for any keyboard event. 146 | # If you press any key in that time, the program continues. 147 | # If 0 is passed, it waits indefinitely for a key stroke. 148 | # (bitwise and with 0xFF to extract least significant byte of 149 | # multi-byte response) 150 | 151 | # wait 40ms (i.e. 1000ms / 25 fps = 40 ms) 152 | key = cv2.waitKey(40) & 0xFF 153 | 154 | # It can also be set to detect specific key strokes by recording which 155 | # key is pressed 156 | 157 | # e.g. if user presses "x" then exit 158 | 159 | if (key == ord('x')): 160 | keep_processing = False 161 | 162 | # close all windows 163 | 164 | cv2.destroyAllWindows() 165 | 166 | else: 167 | print("No usable camera connected.") 168 | 169 | 170 | ##################################################################### 171 | -------------------------------------------------------------------------------- /median_filter.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : median filter on an image from an attached web camera 4 | 5 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 6 | 7 | # Copyright (c) 2015 School of Engineering & Computing Science, 8 | # Copyright (c) 2019 Dept Computer Science, 9 | # Durham University, UK 10 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 11 | 12 | ##################################################################### 13 | 14 | import cv2 15 | import sys 16 | import argparse 17 | 18 | ##################################################################### 19 | 20 | keep_processing = True 21 | 22 | # parse command line arguments for camera ID or video file 23 | 24 | parser = argparse.ArgumentParser( 25 | description='Perform ' + 26 | sys.argv[0] + 27 | ' example operation on incoming camera/video image') 28 | parser.add_argument( 29 | "-c", 30 | "--camera_to_use", 31 | type=int, 32 | help="specify camera to use", 33 | default=0) 34 | parser.add_argument( 35 | "-r", 36 | "--rescale", 37 | type=float, 38 | help="rescale image by this factor", 39 | default=1.0) 40 | parser.add_argument( 41 | 'video_file', 42 | metavar='video_file', 43 | type=str, 44 | nargs='?', 45 | help='specify optional video file') 46 | args = parser.parse_args() 47 | 48 | 49 | ##################################################################### 50 | 51 | # this function is called as a call-back everytime the trackbar is moved 52 | # (here we just do nothing) 53 | 54 | def nothing(x): 55 | pass 56 | 57 | 58 | ##################################################################### 59 | 60 | # define video capture object 61 | 62 | try: 63 | # to use a non-buffered camera stream (via a separate thread) 64 | 65 | if not (args.video_file): 66 | import camera_stream 67 | cap = camera_stream.CameraVideoStream(use_tapi=False) 68 | else: 69 | cap = cv2.VideoCapture() # not needed for video files 70 | 71 | except BaseException: 72 | # if not then just use OpenCV default 73 | 74 | print("INFO: camera_stream class not found - camera input may be buffered") 75 | cap = cv2.VideoCapture() 76 | 77 | # define display window name 78 | 79 | window_name = "Live Camera Input" # window name 80 | window_name2 = "Median Filtering" # window name 81 | 82 | # if command line arguments are provided try to read video_file 83 | # otherwise default to capture from attached H/W camera 84 | 85 | if (((args.video_file) and (cap.open(str(args.video_file)))) 86 | or (cap.open(args.camera_to_use))): 87 | 88 | # create window by name 89 | 90 | cv2.namedWindow(window_name, cv2.WINDOW_AUTOSIZE) 91 | cv2.namedWindow(window_name2, cv2.WINDOW_AUTOSIZE) 92 | 93 | # add some track bar controllers for settings 94 | 95 | neighbourhood = 3 96 | cv2.createTrackbar( 97 | "neighbourhood, N", 98 | window_name2, 99 | neighbourhood, 100 | 40, 101 | nothing) 102 | 103 | while (keep_processing): 104 | 105 | # if video file or camera successfully open then read frame from video 106 | 107 | if (cap.isOpened): 108 | ret, frame = cap.read() 109 | 110 | # when we reach the end of the video (file) exit cleanly 111 | 112 | if (ret == 0): 113 | keep_processing = False 114 | continue 115 | 116 | # rescale if specified 117 | 118 | if (args.rescale != 1.0): 119 | frame = cv2.resize( 120 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 121 | 122 | # get parameter from track bars 123 | 124 | neighbourhood = cv2.getTrackbarPos("neighbourhood, N", window_name2) 125 | 126 | # check it is greater than 3 and odd 127 | 128 | neighbourhood = max(3, neighbourhood) 129 | if not (neighbourhood % 2): 130 | neighbourhood = neighbourhood + 1 131 | 132 | # perform median filtering using NxN neighbourhood 133 | 134 | median_img = cv2.medianBlur(frame, neighbourhood) 135 | 136 | # display image 137 | 138 | cv2.imshow(window_name, frame) 139 | cv2.imshow(window_name2, median_img) 140 | 141 | # start the event loop - essential 142 | 143 | # cv2.waitKey() is a keyboard binding function (argument is the time in 144 | # ms). It waits for specified milliseconds for any keyboard event. 145 | # If you press any key in that time, the program continues. 146 | # If 0 is passed, it waits indefinitely for a key stroke. 147 | # (bitwise and with 0xFF to extract least significant byte of 148 | # multi-byte response) 149 | 150 | # wait 40ms (i.e. 1000ms / 25 fps = 40 ms) 151 | key = cv2.waitKey(40) & 0xFF 152 | 153 | # It can also be set to detect specific key strokes by recording which 154 | # key is pressed 155 | 156 | # e.g. if user presses "x" then exit 157 | 158 | if (key == ord('x')): 159 | keep_processing = False 160 | 161 | # close all windows 162 | 163 | cv2.destroyAllWindows() 164 | 165 | else: 166 | print("No usable camera connected.") 167 | 168 | 169 | ##################################################################### 170 | -------------------------------------------------------------------------------- /nlm_filter.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : mean and non-local means filter on an image from an attached 4 | # web camera 5 | 6 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 7 | 8 | # Copyright (c) 2015 School of Engineering & Computing Science, 9 | # Copyright (c) 2019 Dept Computer Science, 10 | # Durham University, UK 11 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 12 | 13 | ##################################################################### 14 | 15 | import cv2 16 | import sys 17 | import argparse 18 | 19 | ##################################################################### 20 | 21 | keep_processing = True 22 | 23 | # parse command line arguments for camera ID or video file 24 | 25 | parser = argparse.ArgumentParser( 26 | description='Perform ' + 27 | sys.argv[0] + 28 | ' example operation on incoming camera/video image') 29 | parser.add_argument( 30 | "-c", 31 | "--camera_to_use", 32 | type=int, 33 | help="specify camera to use", 34 | default=0) 35 | parser.add_argument( 36 | "-r", 37 | "--rescale", 38 | type=float, 39 | help="rescale image by this factor", 40 | default=1.0) 41 | parser.add_argument( 42 | 'video_file', 43 | metavar='video_file', 44 | type=str, 45 | nargs='?', 46 | help='specify optional video file') 47 | args = parser.parse_args() 48 | 49 | 50 | ##################################################################### 51 | 52 | # this function is called as a call-back everytime the trackbar is moved 53 | # (here we just do nothing) 54 | 55 | def nothing(x): 56 | pass 57 | 58 | 59 | ##################################################################### 60 | 61 | # define video capture object 62 | 63 | try: 64 | # to use a non-buffered camera stream (via a separate thread) 65 | 66 | if not (args.video_file): 67 | import camera_stream 68 | cap = camera_stream.CameraVideoStream(use_tapi=False) 69 | else: 70 | cap = cv2.VideoCapture() # not needed for video files 71 | 72 | except BaseException: 73 | # if not then just use OpenCV default 74 | 75 | print("INFO: camera_stream class not found - camera input may be buffered") 76 | cap = cv2.VideoCapture() 77 | 78 | # define display window name 79 | 80 | window_name = "Live Camera Input" # window name 81 | window_name2 = "Mean Filtering" # window name 82 | window_name3 = "Non-Local Means Filtering" # window name 83 | 84 | # if command line arguments are provided try to read video_file 85 | # otherwise default to capture from attached H/W camera 86 | 87 | if (((args.video_file) and (cap.open(str(args.video_file)))) 88 | or (cap.open(args.camera_to_use))): 89 | 90 | # create window by name 91 | 92 | cv2.namedWindow(window_name, cv2.WINDOW_AUTOSIZE) 93 | cv2.namedWindow(window_name2, cv2.WINDOW_AUTOSIZE) 94 | cv2.namedWindow(window_name3, cv2.WINDOW_AUTOSIZE) 95 | 96 | # add some track bar controllers for settings 97 | 98 | neighbourhood = 7 99 | cv2.createTrackbar( 100 | "neighbourhood, N", 101 | window_name2, 102 | neighbourhood, 103 | 25, 104 | nothing) 105 | search_window = 21 106 | cv2.createTrackbar("search area, W", window_name3, 107 | search_window, 50, nothing) 108 | filter_strength = 10 109 | cv2.createTrackbar( 110 | "strength, h", 111 | window_name3, 112 | filter_strength, 113 | 25, 114 | nothing) 115 | 116 | while (keep_processing): 117 | 118 | # if video file or camera successfully open then read frame from video 119 | 120 | if (cap.isOpened): 121 | ret, frame = cap.read() 122 | 123 | # when we reach the end of the video (file) exit cleanly 124 | 125 | if (ret == 0): 126 | keep_processing = False 127 | continue 128 | 129 | # rescale if specified 130 | 131 | if (args.rescale != 1.0): 132 | frame = cv2.resize( 133 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 134 | 135 | # get parameters from track bars 136 | 137 | neighbourhood = cv2.getTrackbarPos("neighbourhood, N", window_name2) 138 | search_window = cv2.getTrackbarPos("search area, W", window_name3) 139 | filter_strength = cv2.getTrackbarPos("strength, h", window_name3) 140 | 141 | # check neighbourhood is greater than 3 and odd 142 | 143 | neighbourhood = max(3, neighbourhood) 144 | if not (neighbourhood % 2): 145 | neighbourhood = neighbourhood + 1 146 | 147 | # in opencv blur() performs filtering with a NxN kernel where each 148 | # element has a weight of 1 / (N^2) - this is mean filtering 149 | 150 | mean_img = cv2.blur( 151 | frame, 152 | (neighbourhood, 153 | neighbourhood), 154 | borderType=cv2.BORDER_DEFAULT) 155 | 156 | # perform NLM filtering on the same image 157 | 158 | nlm_img = cv2.fastNlMeansDenoisingColored( 159 | frame, 160 | h=filter_strength, 161 | hColor=10, 162 | templateWindowSize=neighbourhood, 163 | searchWindowSize=search_window) 164 | 165 | # display image 166 | 167 | cv2.imshow(window_name, frame) 168 | cv2.imshow(window_name2, mean_img) 169 | cv2.imshow(window_name3, nlm_img) 170 | 171 | # start the event loop - essential 172 | 173 | # cv2.waitKey() is a keyboard binding function (argument is the time in 174 | # ms). It waits for specified milliseconds for any keyboard event. 175 | # If you press any key in that time, the program continues. 176 | # If 0 is passed, it waits indefinitely for a key stroke. 177 | # (bitwise and with 0xFF to extract least significant byte of 178 | # multi-byte response) 179 | 180 | # wait 40ms (i.e. 1000ms / 25 fps = 40 ms) 181 | key = cv2.waitKey(40) & 0xFF 182 | 183 | # It can also be set to detect specific key strokes by recording which 184 | # key is pressed 185 | 186 | # e.g. if user presses "x" then exit 187 | 188 | if (key == ord('x')): 189 | keep_processing = False 190 | 191 | # close all windows 192 | 193 | cv2.destroyAllWindows() 194 | 195 | else: 196 | print("No usable camera connected.") 197 | 198 | 199 | ##################################################################### 200 | -------------------------------------------------------------------------------- /rgb_viewer.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : display individual RGB channels from an video file 4 | # specified on the command line (e.g. python FILE.py video_file) or from an 5 | # attached web camera 6 | 7 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 8 | 9 | # Copyright (c) 2015 School of Engineering & Computing Science, 10 | # Copyright (c) 2019 Dept Computer Science, 11 | # Durham University, UK 12 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 13 | 14 | ##################################################################### 15 | 16 | import cv2 17 | import argparse 18 | import sys 19 | import math 20 | 21 | ##################################################################### 22 | 23 | keep_processing = True 24 | 25 | # parse command line arguments for camera ID or video file 26 | 27 | parser = argparse.ArgumentParser( 28 | description='Perform ' + 29 | sys.argv[0] + 30 | ' example operation on incoming camera/video image') 31 | parser.add_argument( 32 | "-c", 33 | "--camera_to_use", 34 | type=int, 35 | help="specify camera to use", 36 | default=0) 37 | parser.add_argument( 38 | "-r", 39 | "--rescale", 40 | type=float, 41 | help="rescale image by this factor", 42 | default=1.0) 43 | parser.add_argument( 44 | 'video_file', 45 | metavar='video_file', 46 | type=str, 47 | nargs='?', 48 | help='specify optional video file') 49 | args = parser.parse_args() 50 | 51 | ##################################################################### 52 | 53 | # define video capture object 54 | 55 | try: 56 | # to use a non-buffered camera stream (via a separate thread) 57 | 58 | if not (args.video_file): 59 | import camera_stream 60 | cap = camera_stream.CameraVideoStream(use_tapi=False) 61 | else: 62 | cap = cv2.VideoCapture() # not needed for video files 63 | 64 | except BaseException: 65 | # if not then just use OpenCV default 66 | 67 | print("INFO: camera_stream class not found - camera input may be buffered") 68 | cap = cv2.VideoCapture() 69 | 70 | # define display window name 71 | 72 | window_name = "Live Camera Input" # window name 73 | window_name_red = "Red Colour Channel" # window name 74 | window_name_green = "Green Colour Channel" # window name 75 | window_name_blue = "Blue Colour Channel" # window name 76 | 77 | # if command line arguments are provided try to read video_file 78 | # otherwise default to capture from attached H/W camera 79 | 80 | if (((args.video_file) and (cap.open(str(args.video_file)))) 81 | or (cap.open(args.camera_to_use))): 82 | 83 | # create window by name (note flags for resizable or not) 84 | 85 | cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) 86 | 87 | while (keep_processing): 88 | 89 | # if video file or camera successfully open then read frame from video 90 | 91 | if (cap.isOpened): 92 | ret, frame = cap.read() 93 | 94 | # when we reach the end of the video (file) exit cleanly 95 | 96 | if (ret == 0): 97 | keep_processing = False 98 | continue 99 | 100 | # rescale if specified 101 | 102 | if (args.rescale != 1.0): 103 | frame = cv2.resize( 104 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 105 | 106 | # start a timer (to see how long processing and display takes) 107 | 108 | start_t = cv2.getTickCount() 109 | 110 | # display images 111 | 112 | cv2.imshow(window_name, frame) 113 | 114 | # remember colour channels are BGR ordering in OpenCV 115 | 116 | cv2.imshow(window_name_red, frame[:, :, 2]) # red 117 | cv2.imshow(window_name_green, frame[:, :, 1]) # green 118 | cv2.imshow(window_name_blue, frame[:, :, 0]) # green 119 | 120 | # stop the timer and convert to ms. (to see how long processing and 121 | # display takes) 122 | 123 | stop_t = ((cv2.getTickCount() - start_t) / 124 | cv2.getTickFrequency()) * 1000 125 | 126 | # start the event loop - essential 127 | 128 | # cv2.waitKey() is a keyboard binding function (argument is the time in 129 | # ms). It waits for specified milliseconds for any keyboard event. 130 | # If you press any key in that time, the program continues. 131 | # If 0 is passed, it waits indefinitely for a key stroke. 132 | # (bitwise and with 0xFF to extract least significant byte of 133 | # multi-byte response) 134 | 135 | # wait 40ms or less depending on processing time taken (i.e. 1000ms / 136 | # 25 fps = 40 ms) 137 | 138 | key = cv2.waitKey(max(2, 40 - int(math.ceil(stop_t)))) & 0xFF 139 | 140 | # It can also be set to detect specific key strokes by recording which 141 | # key is pressed 142 | 143 | # e.g. if user presses "x" then exit 144 | 145 | if (key == ord('x')): 146 | keep_processing = False 147 | 148 | # close all windows 149 | 150 | cv2.destroyAllWindows() 151 | 152 | else: 153 | print("No video file specified or camera connected.") 154 | 155 | ##################################################################### 156 | -------------------------------------------------------------------------------- /save_image.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : save an image from file (and invert it) 4 | 5 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 6 | 7 | # Copyright (c) 2015 School of Engineering & Computing Science, 8 | # Durham University, UK 9 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 10 | 11 | ##################################################################### 12 | 13 | import cv2 14 | 15 | ##################################################################### 16 | 17 | # read an image from the specified file (in colour) 18 | 19 | img = cv2.imread('example.jpg', cv2.IMREAD_COLOR) 20 | 21 | # check it has loaded 22 | 23 | if img is not None: 24 | 25 | # performing logical inversion (see manual entry for bitwise_not () 26 | 27 | inverted = cv2.bitwise_not(img) 28 | 29 | # write inverted image to file 30 | 31 | cv2.imwrite("inverted.jpg", inverted) 32 | 33 | else: 34 | print("No image file successfully loaded.") 35 | 36 | ##################################################################### 37 | -------------------------------------------------------------------------------- /save_video.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : generic example for video processing from a video file 4 | # specified as video.avi or from an 5 | # attached web camera and saving to a video file 6 | 7 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 8 | 9 | # Copyright (c) 2015 School of Engineering & Computing Science, 10 | # Copyright (c) 2019 Dept Computer Science, 11 | # Durham University, UK 12 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 13 | 14 | ##################################################################### 15 | 16 | import cv2 17 | import argparse 18 | import sys 19 | 20 | ##################################################################### 21 | 22 | keep_processing = True 23 | 24 | # parse command line arguments for camera ID or video file 25 | 26 | parser = argparse.ArgumentParser( 27 | description='Perform ' + 28 | sys.argv[0] + 29 | ' example operation on incoming camera/video image') 30 | parser.add_argument( 31 | "-c", 32 | "--camera_to_use", 33 | type=int, 34 | help="specify camera to use", 35 | default=0) 36 | parser.add_argument( 37 | "-r", 38 | "--rescale", 39 | type=float, 40 | help="rescale image by this factor", 41 | default=1.0) 42 | args = parser.parse_args() 43 | 44 | video_width = 640 45 | video_height = 480 46 | 47 | ##################################################################### 48 | 49 | # define video capture object 50 | 51 | try: 52 | # to use a non-buffered camera stream (via a separate thread) 53 | 54 | import camera_stream 55 | cap = camera_stream.CameraVideoStream(use_tapi=False) 56 | 57 | except BaseException: 58 | # if not then just use OpenCV default 59 | 60 | print("INFO: camera_stream class not found - camera input may be buffered") 61 | cap = cv2.VideoCapture() 62 | 63 | # define display window name 64 | 65 | window_name = "Live Camera Input -> Video File" # window name 66 | 67 | # define video writer (video: 640 x 480 @ 25 fps) 68 | 69 | fourcc = cv2.VideoWriter_fourcc('M', 'J', 'P', 'G') 70 | output = cv2.VideoWriter('output.avi', fourcc, 25.0, 71 | (video_width, video_height)) 72 | 73 | # if command line arguments are provided try to read video_file 74 | # otherwise default to capture from attached H/W camera 75 | 76 | if ((cap.open("input.avi")) or (cap.open(args.camera_to_use))): 77 | 78 | # create window by name (as resizable) 79 | 80 | cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) 81 | 82 | while (keep_processing): 83 | 84 | # if video file or camera successfully open then read frame from video 85 | 86 | if (cap.isOpened): 87 | ret, frame = cap.read() 88 | 89 | # when we reach the end of the video (file) exit cleanly 90 | 91 | if (ret == 0): 92 | keep_processing = False 93 | continue 94 | 95 | # rescale if specified 96 | 97 | if (args.rescale != 1.0): 98 | frame = cv2.resize( 99 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 100 | 101 | # *** do any processing here **** 102 | 103 | # write the frame to file (first resizing) 104 | 105 | frame2 = cv2.resize( 106 | frame, 107 | (video_width, 108 | video_height), 109 | interpolation=cv2.INTER_CUBIC) 110 | output.write(frame2) 111 | 112 | # display image 113 | 114 | cv2.imshow(window_name, frame) 115 | 116 | # start the event loop - essential 117 | 118 | # cv2.waitKey() is a keyboard binding function (argument is the time in 119 | # ms). It waits for specified milliseconds for any keyboard event. 120 | # If you press any key in that time, the program continues. 121 | # If 0 is passed, it waits indefinitely for a key stroke. 122 | # (bitwise and with 0xFF to extract least significant byte of 123 | # multi-byte response) 124 | 125 | key = cv2.waitKey(1) & 0xFF # wait 1ms only 126 | 127 | # e.g. if user presses "x" then exit 128 | 129 | if (key == ord('x')): 130 | keep_processing = False 131 | 132 | # close all windows 133 | 134 | cv2.destroyAllWindows() 135 | 136 | # Release everything if job is finished 137 | cap.release() 138 | output.release() 139 | 140 | else: 141 | print("No video file specified or camera connected.") 142 | 143 | ##################################################################### 144 | -------------------------------------------------------------------------------- /skeleton.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : <................................> processing from a video file 4 | # specified on the command line (e.g. python FILE.py video_file) or from an 5 | # attached web camera 6 | 7 | # Author : , @durham.ac.uk 8 | 9 | # Copyright (c) 20xx 10 | # Durham University, UK 11 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 12 | 13 | ##################################################################### 14 | 15 | import cv2 16 | import argparse 17 | import sys 18 | import math 19 | 20 | ##################################################################### 21 | 22 | keep_processing = True 23 | 24 | # parse command line arguments for camera ID or video file 25 | 26 | parser = argparse.ArgumentParser( 27 | description='Perform ' + 28 | sys.argv[0] + 29 | ' example operation on incoming camera/video image') 30 | parser.add_argument( 31 | "-c", 32 | "--camera_to_use", 33 | type=int, 34 | help="specify camera to use", 35 | default=0) 36 | parser.add_argument( 37 | "-r", 38 | "--rescale", 39 | type=float, 40 | help="rescale image by this factor", 41 | default=1.0) 42 | parser.add_argument( 43 | 'video_file', 44 | metavar='video_file', 45 | type=str, 46 | nargs='?', 47 | help='specify optional video file') 48 | args = parser.parse_args() 49 | 50 | ##################################################################### 51 | 52 | # define video capture object 53 | 54 | try: 55 | # to use a non-buffered camera stream (via a separate thread) 56 | 57 | if not (args.video_file): 58 | import camera_stream 59 | cap = camera_stream.CameraVideoStream(use_tapi=False) 60 | else: 61 | cap = cv2.VideoCapture() # not needed for video files 62 | 63 | except BaseException: 64 | # if not then just use OpenCV default 65 | 66 | print("INFO: camera_stream class not found - camera input may be buffered") 67 | cap = cv2.VideoCapture() 68 | 69 | # define display window name 70 | 71 | window_name = "Live Camera Input" # window name 72 | 73 | # if command line arguments are provided try to read video_file 74 | # otherwise default to capture from attached H/W camera 75 | 76 | if (((args.video_file) and (cap.open(str(args.video_file)))) 77 | or (cap.open(args.camera_to_use))): 78 | 79 | # create window by name (note flags for resizable or not) 80 | 81 | cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) 82 | 83 | while (keep_processing): 84 | 85 | # if video file or camera successfully open then read frame from video 86 | 87 | if (cap.isOpened): 88 | ret, frame = cap.read() 89 | 90 | # when we reach the end of the video (file) exit cleanly 91 | 92 | if (ret == 0): 93 | keep_processing = False 94 | continue 95 | 96 | # rescale if specified 97 | 98 | if (args.rescale != 1.0): 99 | frame = cv2.resize( 100 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 101 | 102 | # start a timer (to see how long processing and display takes) 103 | 104 | start_t = cv2.getTickCount() 105 | 106 | # ******************************* 107 | 108 | # *** do any processing here **** 109 | 110 | # ******************************* 111 | 112 | # display image 113 | 114 | cv2.imshow(window_name, frame) 115 | 116 | # stop the timer and convert to ms. (to see how long processing and 117 | # display takes) 118 | 119 | stop_t = ((cv2.getTickCount() - start_t) / 120 | cv2.getTickFrequency()) * 1000 121 | 122 | # start the event loop - essential 123 | 124 | # cv2.waitKey() is a keyboard binding function (argument is the time in 125 | # ms). It waits for specified milliseconds for any keyboard event. 126 | # If you press any key in that time, the program continues. 127 | # If 0 is passed, it waits indefinitely for a key stroke. 128 | # (bitwise and with 0xFF to extract least significant byte of 129 | # multi-byte response) 130 | 131 | # wait 40ms or less depending on processing time taken (i.e. 1000ms / 132 | # 25 fps = 40 ms) 133 | 134 | key = cv2.waitKey(max(2, 40 - int(math.ceil(stop_t)))) & 0xFF 135 | 136 | # It can also be set to detect specific key strokes by recording which 137 | # key is pressed 138 | 139 | # e.g. if user presses "x" then exit 140 | 141 | if (key == ord('x')): 142 | keep_processing = False 143 | 144 | # close all windows 145 | 146 | cv2.destroyAllWindows() 147 | 148 | else: 149 | print("No video file specified or camera connected.") 150 | 151 | ##################################################################### 152 | -------------------------------------------------------------------------------- /smooth_image.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : displaying an image from file (and smoothing it) 4 | 5 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 6 | 7 | # Copyright (c) 2015 School of Engineering & Computing Science, 8 | # Durham University, UK 9 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 10 | 11 | ##################################################################### 12 | 13 | import cv2 14 | 15 | ##################################################################### 16 | 17 | # define display window name 18 | 19 | window_name = "Smoothed Image" # window name 20 | 21 | # read an image from the specified file (in colour) 22 | 23 | img = cv2.imread('example.jpg', cv2.IMREAD_COLOR) 24 | 25 | # check it has loaded 26 | 27 | if img is not None: 28 | 29 | # performing smoothing on the image using a 5x5 smoothing mark (see manual 30 | # entry for GaussianBlur()) 31 | 32 | blur = cv2.GaussianBlur(img, (5, 5), 0) 33 | 34 | # display this blurred image in a named window 35 | 36 | cv2.imshow(window_name, blur) 37 | 38 | # start the event loop - essential 39 | 40 | # cv2.waitKey() is a keyboard binding function (argument is the time in 41 | # ms). It waits for specified milliseconds for any keyboard event. 42 | # If you press any key in that time, the program continues. 43 | # If 0 is passed, it waits indefinitely for a key stroke. 44 | # (bitwise and with 0xFF to extract least significant byte of 45 | # multi-byte response) 46 | 47 | key = cv2.waitKey(0) & 0xFF # wait 48 | 49 | # It can also be set to detect specific key strokes by recording which key 50 | # is pressed 51 | 52 | # e.g. if user presses "x" then exit and close all windows 53 | 54 | if (key == ord('x')): 55 | cv2.destroyAllWindows() 56 | else: 57 | print("No image file successfully loaded.") 58 | 59 | ##################################################################### 60 | -------------------------------------------------------------------------------- /test_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ################################################################################ 4 | 5 | # run a batch test over all the examples from the bash shell (linux) 6 | 7 | # Copyright (c) 2019 Dept Computer Science, 8 | # Durham University, UK 9 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 10 | 11 | ################################################################################ 12 | 13 | PYTHON_INTERPRETATOR=python3 14 | CAM_TO_TEST=0 15 | VIDEO_TO_TEST=video.avi 16 | 17 | echo 18 | echo Using $PYTHON_INTERPRETATOR with camera $CAM_TO_TEST and video $VIDEO_TO_TEST 19 | echo "Running test suite - press 'x' in OpenCV window to exit each example." 20 | echo 21 | 22 | # get testing resouces if they do not exist 23 | 24 | [ -f example.jpg ] || { wget https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg; mv JPEG_example_JPG_RIP_100.jpg example.jpg; } 25 | [ -f video.avi ] || { wget http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4; mv big_buck_bunny.mp4 video.avi; } 26 | 27 | ################################################################################ 28 | 29 | # run defaults 30 | 31 | echo "Running default tests ..." 32 | echo 33 | 34 | for example in *.py 35 | do 36 | echo "Testing example: " $example 37 | $PYTHON_INTERPRETATOR $example 38 | echo 39 | done 40 | 41 | ################################################################################ 42 | 43 | # run cam test 44 | 45 | echo "Running camera based tests ..." 46 | echo 47 | 48 | for example in *.py 49 | do 50 | echo "Testing example: " $example -c $CAM_TO_TEST 51 | $PYTHON_INTERPRETATOR $example -c $CAM_TO_TEST 52 | echo 53 | done 54 | 55 | ################################################################################ 56 | 57 | # run cam test and resize 58 | 59 | echo "Running camera based tests with resizing ..." 60 | echo 61 | 62 | for example in *.py 63 | do 64 | echo "Testing example: " $example -c $CAM_TO_TEST -r 0.25 65 | $PYTHON_INTERPRETATOR $example -c $CAM_TO_TEST -r 0.25 66 | echo 67 | done 68 | 69 | 70 | ################################################################################ 71 | 72 | # run video file test 73 | 74 | echo "Running video file based tests ..." 75 | echo 76 | 77 | for example in *.py 78 | do 79 | echo "Testing example: " $example $VIDEO_TO_TEST 80 | $PYTHON_INTERPRETATOR $example $VIDEO_TO_TEST 81 | echo 82 | done 83 | 84 | ################################################################################ 85 | -------------------------------------------------------------------------------- /version.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : test if opencv environment is working 4 | 5 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 6 | 7 | # Copyright (c) 2017-2022 Toby Breckon, Durham University, UK 8 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 9 | 10 | ##################################################################### 11 | 12 | import cv2 13 | import numpy as np 14 | import sys 15 | import re 16 | import struct 17 | import matplotlib 18 | 19 | ##################################################################### 20 | 21 | # check if the OpenCV we are using has the extra modules available 22 | 23 | 24 | def extra_opencv_modules_present(): 25 | (is_built, not_built) = cv2.getBuildInformation().split("Disabled:") 26 | return ('xfeatures2d' in is_built) 27 | 28 | 29 | def non_free_opencv_algorithms_present(): 30 | (before, after) = cv2.getBuildInformation().split("Non-free algorithms:") 31 | output_list = after.split("\n") 32 | return ('YES' in output_list[0]) 33 | 34 | 35 | ##################################################################### 36 | 37 | print() 38 | print("We are using OpenCV: " + cv2.__version__) 39 | print(".. do we have the OpenCV Contrib Modules: " + 40 | str(extra_opencv_modules_present())) 41 | try: 42 | print(".. do we have the OpenCV Non-free algorithms: " + 43 | str(non_free_opencv_algorithms_present())) 44 | except BaseException: 45 | print(".. OpenCV version pre-dates (or does not have) " + 46 | "non-free algorithms module") 47 | try: 48 | print(".. do we have the Intel Performance Primitives (IPP): \n" + 49 | ".. version: " + str(cv2.ipp.getIppVersion()) + " (in use: " 50 | + str(cv2.ipp.useIPP()) + " )") 51 | except BaseException: 52 | print(".. OpenCV version does not have " + 53 | "Intel Performance Primitives (IPP)") 54 | print("We are using numpy: " + np.__version__) 55 | print("We are using matplotlib: " + matplotlib.__version__) 56 | print(".. and this is in Python: " + sys.version + 57 | " (" + str(struct.calcsize("P") * 8) + " bit)") 58 | 59 | ##################################################################### 60 | 61 | print() 62 | print("Check Video I/O (OS identifier: " + sys.platform + ")") 63 | print("... available camera backends: ", end='') 64 | for backend in cv2.videoio_registry.getCameraBackends(): 65 | print(" " + cv2.videoio_registry.getBackendName(backend), end='') 66 | print() 67 | print("... available stream backends: ", end='') 68 | for backend in cv2.videoio_registry.getStreamBackends(): 69 | print(" " + cv2.videoio_registry.getBackendName(backend), end='') 70 | print() 71 | print("... available video writer backends: ", end='') 72 | for backend in cv2.videoio_registry.getWriterBackends(): 73 | print(" " + cv2.videoio_registry.getBackendName(backend), end='') 74 | print() 75 | print() 76 | 77 | ##################################################################### 78 | 79 | # credit to: https://tinyurl.com/y529vzc3 80 | 81 | print("Available Cuda Information: ") 82 | cuda_info = [re.sub('\\s+', ' ', ci.strip()) for ci in 83 | cv2.getBuildInformation().strip().split('\n') 84 | if len(ci) > 0 and re.search(r'(nvidia*:?)|(cuda*:)|(cudnn*:)', 85 | ci.lower()) is not None] 86 | print("... " + str(cuda_info)) 87 | print() 88 | 89 | ##################################################################### 90 | 91 | try: 92 | for gpu in range(cv2.cuda.getCudaEnabledDeviceCount()): 93 | print("CUDA enabled GPU device index: " + str(gpu) + " ") 94 | cv2.cuda.printShortCudaDeviceInfo(gpu) 95 | print() 96 | except BaseException: 97 | print("No CUDA enabled devices found : " + 98 | "[none present or in powered down state]") 99 | 100 | ##################################################################### 101 | 102 | print("DNN module CUDA backend/target availability : ", end='') 103 | try: 104 | targets = cv2.dnn.getAvailableTargets(cv2.dnn.DNN_BACKEND_CUDA) 105 | print() 106 | print("... DNN_TARGET_CUDA: \t\t", end='') 107 | print(cv2.dnn.DNN_TARGET_CUDA in targets) 108 | print("... DNN_TARGET_CUDA_FP16: \t", end='') 109 | print(cv2.dnn.DNN_TARGET_CUDA_FP16 in targets) 110 | targets = cv2.dnn.getAvailableTargets(cv2.dnn.DNN_BACKEND_DEFAULT) 111 | print("... DNN_TARGET_CPU: \t\t", end='') 112 | print(cv2.dnn.DNN_TARGET_CPU in targets) 113 | print("... DNN_TARGET_OPENCL: \t\t", end='') 114 | print(cv2.dnn.DNN_TARGET_OPENCL in targets) 115 | print("... DNN_TARGET_OPENCL_FP16: \t", end='') 116 | print(cv2.dnn.DNN_TARGET_OPENCL_FP16 in targets) 117 | except BaseException: 118 | print("False") 119 | 120 | ##################################################################### 121 | 122 | print() 123 | print("OpenCL available (within OpenCV) ? : " + str(cv2.ocl.haveOpenCL())) 124 | print() 125 | 126 | ##################################################################### 127 | 128 | print("Available CPU Optimizations (*: build enabled; ?: not CPU supported):") 129 | try: 130 | print("... " + cv2.getCPUFeaturesLine()) 131 | print() 132 | except BaseException: 133 | print("... [ CPU feature check not available in this version ]") 134 | print() 135 | 136 | ##################################################################### 137 | -------------------------------------------------------------------------------- /ycrcb_viewer.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | 3 | # Example : display individual YCrCb channels from an video file 4 | # specified on the command line (e.g. python FILE.py video_file) or from an 5 | # attached web camera (with optional chroma subsampling as used in JPEG 6 | # image compression) 7 | 8 | # Author : Toby Breckon, toby.breckon@durham.ac.uk 9 | 10 | # Copyright (c) 2020 Dept Computer Science, Durham University, UK 11 | # License : LGPL - http://www.gnu.org/licenses/lgpl.html 12 | 13 | ##################################################################### 14 | 15 | import cv2 16 | import argparse 17 | import sys 18 | import math 19 | 20 | ##################################################################### 21 | 22 | keep_processing = True 23 | 24 | # parse command line arguments for camera ID or video file 25 | 26 | parser = argparse.ArgumentParser( 27 | description='Perform ' + 28 | sys.argv[0] + 29 | ' example operation on incoming camera/video image') 30 | parser.add_argument( 31 | "-c", 32 | "--camera_to_use", 33 | type=int, 34 | help="specify camera to use", 35 | default=0) 36 | parser.add_argument( 37 | "-r", 38 | "--rescale", 39 | type=float, 40 | help="rescale image by this factor", 41 | default=1.0) 42 | parser.add_argument( 43 | 'video_file', 44 | metavar='video_file', 45 | type=str, 46 | nargs='?', 47 | help='specify optional video file') 48 | args = parser.parse_args() 49 | 50 | 51 | perform_chroma_subsampling = False 52 | 53 | ##################################################################### 54 | 55 | # define video capture object 56 | 57 | try: 58 | # to use a non-buffered camera stream (via a separate thread) 59 | 60 | if not (args.video_file): 61 | import camera_stream 62 | cap = camera_stream.CameraVideoStream(use_tapi=False) 63 | else: 64 | cap = cv2.VideoCapture() # not needed for video files 65 | 66 | except BaseException: 67 | # if not then just use OpenCV default 68 | 69 | print("INFO: camera_stream class not found - camera input may be buffered") 70 | cap = cv2.VideoCapture() 71 | 72 | # define display window name 73 | 74 | window_name = "Live Camera Input" # window name 75 | window_name_y = "Y Channel" # window name 76 | window_name_cr = "Cr Channel" # window name 77 | window_name_cb = "Cb Channel" # window name 78 | 79 | # if command line arguments are provided try to read video_file 80 | # otherwise default to capture from attached H/W camera 81 | 82 | if (((args.video_file) and (cap.open(str(args.video_file)))) 83 | or (cap.open(args.camera_to_use))): 84 | 85 | # create window by name (note flags for resizable or not) 86 | 87 | cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) 88 | 89 | # usage 90 | 91 | print("USAGE: press 's' to subsample the chroma") 92 | 93 | while (keep_processing): 94 | 95 | # if video file or camera successfully open then read frame from video 96 | 97 | if (cap.isOpened): 98 | ret, frame = cap.read() 99 | 100 | # when we reach the end of the video (file) exit cleanly 101 | 102 | if (ret == 0): 103 | keep_processing = False 104 | continue 105 | 106 | # rescale if specified 107 | 108 | if (args.rescale != 1.0): 109 | frame = cv2.resize( 110 | frame, (0, 0), fx=args.rescale, fy=args.rescale) 111 | 112 | # start a timer (to see how long processing and display takes) 113 | 114 | start_t = cv2.getTickCount() 115 | 116 | img_ycrcb = cv2.cvtColor(frame, cv2.COLOR_BGR2YCrCb) 117 | 118 | # subsample the chroma information in the same way as it is done in 119 | # JPEG 120 | 121 | if (perform_chroma_subsampling): 122 | 123 | # "Next, the chrominance channels Cr and Cb are subsampled. 124 | # The constant SSH defines the subsampling factor in horicontal 125 | # direction, SSV defines the vertical subsampling factor. Before 126 | # subsampling the chrominance channels are filtered using a (2x2) 127 | # box filter (=average filter). ..." Code from: 128 | # https://www.hdm-stuttgart.de/~maucher/Python/MMCodecs/html/jpegUpToQuant.html 129 | 130 | SSV = 2 131 | SSH = 2 132 | crf = cv2.boxFilter(img_ycrcb[:, :, 1], ddepth=-1, ksize=(2, 2)) 133 | cbf = cv2.boxFilter(img_ycrcb[:, :, 2], ddepth=-1, ksize=(2, 2)) 134 | crsub = crf[::SSV, ::SSH] 135 | cbsub = cbf[::SSV, ::SSH] 136 | 137 | # display images 138 | 139 | cv2.imshow(window_name, frame) 140 | 141 | # colour channels are YCrCb ordering in OpenCV 142 | 143 | cv2.imshow(window_name_y, img_ycrcb[:, :, 0]) # Y 144 | if (perform_chroma_subsampling): 145 | cv2.imshow(window_name_cr, crsub) # Cr 146 | cv2.imshow(window_name_cb, cbsub) # Cb 147 | else: 148 | cv2.imshow(window_name_cr, img_ycrcb[:, :, 1]) # Cr 149 | cv2.imshow(window_name_cb, img_ycrcb[:, :, 2]) # Cb 150 | 151 | # stop the timer and convert to ms. (to see how long processing and 152 | # display takes) 153 | 154 | stop_t = ((cv2.getTickCount() - start_t) / 155 | cv2.getTickFrequency()) * 1000 156 | 157 | # start the event loop - essential 158 | 159 | # cv2.waitKey() is a keyboard binding function (argument is the time in 160 | # ms). It waits for specified milliseconds for any keyboard event. 161 | # If you press any key in that time, the program continues. 162 | # If 0 is passed, it waits indefinitely for a key stroke. 163 | # (bitwise and with 0xFF to extract least significant byte of 164 | # multi-byte response) 165 | 166 | # wait 40ms or less depending on processing time taken (i.e. 1000ms / 167 | # 25 fps = 40 ms) 168 | 169 | key = cv2.waitKey(max(2, 40 - int(math.ceil(stop_t)))) & 0xFF 170 | 171 | # It can also be set to detect specific key strokes by recording which 172 | # key is pressed 173 | 174 | # e.g. if user presses "x" then exit 175 | 176 | if (key == ord('x')): 177 | keep_processing = False 178 | elif (key == ord('s')): 179 | perform_chroma_subsampling = not (perform_chroma_subsampling) 180 | 181 | # close all windows 182 | 183 | cv2.destroyAllWindows() 184 | 185 | else: 186 | print("No video file specified or camera connected.") 187 | 188 | ##################################################################### 189 | --------------------------------------------------------------------------------