├── img └── dnld_rep.png ├── 04_Sobel_Filter └── lena_gray.jpg ├── 02_Canny_Edge_Detection └── lena_gray.jpg ├── 07_Image_Manipulation └── color_circle.png ├── 03_Eigen_Faces └── Eigenfaces │ ├── Test │ ├── Thumbs.db │ ├── S034_005_02293928.jpg │ ├── S035_005_02500507.jpg │ ├── S045_001_00155520.jpg │ ├── S046_004_00021029.jpg │ ├── S050_003_00015829.jpg │ ├── S053_001_00022401.jpg │ ├── S054_001_00021023.jpg │ ├── S055_005_01065417.jpg │ ├── S056_001_01175021.jpg │ ├── S057_006_01271600.jpg │ ├── S059_002_00121512.jpg │ ├── S060_001_00211719.jpg │ ├── S063_001_00223923.jpg │ ├── S066_002_00232526.jpg │ ├── S072_004_00012819.jpg │ ├── S074_001_00222227.jpg │ ├── S074_005_00222617.jpg │ ├── S075_007_00324804.jpg │ ├── S076_005_00014211.jpg │ ├── S077_003_00092609.jpg │ ├── S078_001_00014700.jpg │ ├── S078_006_00001803.jpg │ ├── S080_001_00214925.jpg │ ├── S080_002_00215618.jpg │ ├── S081_003_00005417.jpg │ ├── S099_001_123450_1.jpg │ ├── S099_001_123450_2.jpg │ ├── S099_001_123450_3.jpg │ ├── S099_001_123450_4.jpg │ ├── S099_001_123450_5.jpg │ ├── S099_001_123450_6.jpg │ └── S099_001_123450_8.jpg │ └── Train │ ├── S022_001_00021318.jpg │ ├── S026_004_01383021.jpg │ ├── S054_001_00021021.jpg │ ├── S055_003_01064023.jpg │ ├── S056_001_01175019.jpg │ ├── S057_001_01270613.jpg │ ├── S058_002_00021024.jpg │ ├── S059_003_00122227.jpg │ ├── S060_002_00210427.jpg │ ├── S061_001_00015910.jpg │ ├── S063_002_00224514.jpg │ ├── S064_002_00013117.jpg │ ├── S065_001_00125727.jpg │ ├── S066_001_00232825.jpg │ ├── S067_001_00021900.jpg │ ├── S071_002_00242705.jpg │ ├── S072_001_00004521.jpg │ ├── S073_002_00121301.jpg │ ├── S074_001_00222211.jpg │ ├── S075_001_00332215.jpg │ ├── S076_002_00005728.jpg │ ├── S077_001_00100209.jpg │ ├── S078_001_00014622.jpg │ ├── S079_003_00111414.jpg │ └── S080_003_00204412.jpg ├── 01_Dynamic_Time_Warping ├── A3VPKJJ0GMVJSNXICNJ5L5Y9JT9K2YKT.png ├── BWQ6YDNCD5RH21TRCV6K7URPA05UCM0T.png ├── PMCFBXFYO2WUX5EPRCQM0K8DALBYR0KB.png ├── V4VW3VNNRET6TKXJW2MR0A024BD0EMUM.png └── Dynamic_Time_Warping.ipynb ├── LICENSE ├── README.md ├── 05_Hough_Line_Detection └── Hough_Lines.ipynb └── 06_Feature_Detection └── Feature_Detection.ipynb /img/dnld_rep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/img/dnld_rep.png -------------------------------------------------------------------------------- /04_Sobel_Filter/lena_gray.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/04_Sobel_Filter/lena_gray.jpg -------------------------------------------------------------------------------- /02_Canny_Edge_Detection/lena_gray.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/02_Canny_Edge_Detection/lena_gray.jpg -------------------------------------------------------------------------------- /07_Image_Manipulation/color_circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/07_Image_Manipulation/color_circle.png -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/Thumbs.db -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S034_005_02293928.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S034_005_02293928.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S035_005_02500507.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S035_005_02500507.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S045_001_00155520.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S045_001_00155520.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S046_004_00021029.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S046_004_00021029.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S050_003_00015829.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S050_003_00015829.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S053_001_00022401.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S053_001_00022401.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S054_001_00021023.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S054_001_00021023.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S055_005_01065417.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S055_005_01065417.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S056_001_01175021.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S056_001_01175021.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S057_006_01271600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S057_006_01271600.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S059_002_00121512.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S059_002_00121512.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S060_001_00211719.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S060_001_00211719.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S063_001_00223923.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S063_001_00223923.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S066_002_00232526.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S066_002_00232526.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S072_004_00012819.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S072_004_00012819.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S074_001_00222227.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S074_001_00222227.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S074_005_00222617.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S074_005_00222617.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S075_007_00324804.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S075_007_00324804.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S076_005_00014211.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S076_005_00014211.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S077_003_00092609.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S077_003_00092609.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S078_001_00014700.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S078_001_00014700.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S078_006_00001803.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S078_006_00001803.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S080_001_00214925.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S080_001_00214925.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S080_002_00215618.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S080_002_00215618.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S081_003_00005417.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S081_003_00005417.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S099_001_123450_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S099_001_123450_1.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S099_001_123450_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S099_001_123450_2.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S099_001_123450_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S099_001_123450_3.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S099_001_123450_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S099_001_123450_4.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S099_001_123450_5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S099_001_123450_5.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S099_001_123450_6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S099_001_123450_6.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Test/S099_001_123450_8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Test/S099_001_123450_8.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S022_001_00021318.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S022_001_00021318.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S026_004_01383021.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S026_004_01383021.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S054_001_00021021.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S054_001_00021021.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S055_003_01064023.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S055_003_01064023.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S056_001_01175019.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S056_001_01175019.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S057_001_01270613.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S057_001_01270613.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S058_002_00021024.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S058_002_00021024.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S059_003_00122227.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S059_003_00122227.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S060_002_00210427.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S060_002_00210427.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S061_001_00015910.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S061_001_00015910.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S063_002_00224514.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S063_002_00224514.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S064_002_00013117.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S064_002_00013117.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S065_001_00125727.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S065_001_00125727.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S066_001_00232825.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S066_001_00232825.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S067_001_00021900.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S067_001_00021900.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S071_002_00242705.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S071_002_00242705.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S072_001_00004521.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S072_001_00004521.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S073_002_00121301.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S073_002_00121301.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S074_001_00222211.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S074_001_00222211.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S075_001_00332215.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S075_001_00332215.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S076_002_00005728.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S076_002_00005728.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S077_001_00100209.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S077_001_00100209.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S078_001_00014622.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S078_001_00014622.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S079_003_00111414.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S079_003_00111414.jpg -------------------------------------------------------------------------------- /03_Eigen_Faces/Eigenfaces/Train/S080_003_00204412.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/03_Eigen_Faces/Eigenfaces/Train/S080_003_00204412.jpg -------------------------------------------------------------------------------- /01_Dynamic_Time_Warping/A3VPKJJ0GMVJSNXICNJ5L5Y9JT9K2YKT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/01_Dynamic_Time_Warping/A3VPKJJ0GMVJSNXICNJ5L5Y9JT9K2YKT.png -------------------------------------------------------------------------------- /01_Dynamic_Time_Warping/BWQ6YDNCD5RH21TRCV6K7URPA05UCM0T.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/01_Dynamic_Time_Warping/BWQ6YDNCD5RH21TRCV6K7URPA05UCM0T.png -------------------------------------------------------------------------------- /01_Dynamic_Time_Warping/PMCFBXFYO2WUX5EPRCQM0K8DALBYR0KB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/01_Dynamic_Time_Warping/PMCFBXFYO2WUX5EPRCQM0K8DALBYR0KB.png -------------------------------------------------------------------------------- /01_Dynamic_Time_Warping/V4VW3VNNRET6TKXJW2MR0A024BD0EMUM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/milaan9/Python_Computer_Vision_from_Scratch/HEAD/01_Dynamic_Time_Warping/V4VW3VNNRET6TKXJW2MR0A024BD0EMUM.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Milaan Parmar / Милан пармар / _米兰 帕尔马 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Last Commit 3 | 4 | 5 | 6 | 7 | Stars Badge 8 | Forks Badge 9 | Size 10 | Pull Requests Badge 11 | Issues Badge 12 | Language 13 | MIT License 14 |

15 | 16 |

17 | binder 18 | colab 19 |

20 | 21 | 22 | # Python_Computer_Vision_from_Scratch 23 | 24 | ## Introduction 👋 25 | 26 | This repository explores the variety of techniques commonly used to analyze and interpret images. It also describes challenging real-world applications where vision is being successfully used, both for specialized applications such as medical imaging, and for fun, consumer-level tasks such as image editing and stitching, which students can apply to their own personal photos and videos. 27 | 28 | --- 29 | 30 | ## Table of contents 📋 31 | 32 | | **No.** | **Name** | 33 | | ------- | -------- | 34 | | 01 | **[Dynamic_Time_Warping](https://github.com/milaan9/Python_Computer_Vision_from_Scratch/tree/main/01_Dynamic_Time_Warping)** | 35 | | 02 | **[Canny_Edge_Detection](https://github.com/milaan9/Python_Computer_Vision_from_Scratch/tree/main/02_Canny_Edge_Detection)** | 36 | | 03 | **[Eigen_Faces](https://github.com/milaan9/Python_Computer_Vision_from_Scratch/tree/main/03_Eigen_Faces)** | 37 | | 04 | **[Sobel_Filter](https://github.com/milaan9/Python_Computer_Vision_from_Scratch/tree/main/04_Sobel_Filter)** | 38 | | 05 | **[Hough_Line_Detection](https://github.com/milaan9/Python_Computer_Vision_from_Scratch/tree/main/05_Hough_Line_Detection)** | 39 | | 06 | **[Feature_Detection](https://github.com/milaan9/Python_Computer_Vision_from_Scratch/tree/main/06_Feature_Detection)** | 40 | | 07 | **[Image_Manipulation](https://github.com/milaan9/Python_Computer_Vision_from_Scratch/tree/main/07_Image_Manipulation)** | 41 | 42 | These are online **read-only** versions. However you can **`Run ▶`** all the codes **online** by clicking here ➞ binder 43 | 44 | --- 45 | 46 | ## Frequently asked questions ❔ 47 | 48 | ### How can I thank you for writing and sharing this tutorial? 🌷 49 | 50 | You can Star Badge and Fork Badge Starring and Forking is free for you, but it tells me and other people that it was helpful and you like this tutorial. 51 | 52 | Go [**`here`**](https://github.com/milaan9/Python_Computer_Vision_from_Scratch) if you aren't here already and click ➞ **`✰ Star`** and **`ⵖ Fork`** button in the top right corner. You'll be asked to create a GitHub account if you don't already have one. 53 | 54 | --- 55 | 56 | ### How can I read this tutorial without an Internet connection? GIF 57 | 58 | 1. Go [**`here`**](https://github.com/milaan9/Python_Computer_Vision_from_Scratch) and click the big green ➞ **`Code`** button in the top right of the page, then click ➞ [**`Download ZIP`**](https://github.com/milaan9/Python_Computer_Vision_from_Scratch/archive/refs/heads/main.zip). 59 | 60 | ![Download ZIP](img/dnld_rep.png) 61 | 62 | 2. Extract the ZIP and open it. Unfortunately I don't have any more specific instructions because how exactly this is done depends on which operating system you run. 63 | 64 | 3. Launch ipython notebook from the folder which contains the notebooks. Open each one of them 65 | 66 | **`Kernel > Restart & Clear Output`** 67 | 68 | This will clear all the outputs and now you can understand each statement and learn interactively. 69 | 70 | If you have git and you know how to use it, you can also clone the repository instead of downloading a zip and extracting it. An advantage with doing it this way is that you don't need to download the whole tutorial again to get the latest version of it, all you need to do is to pull with git and run ipython notebook again. 71 | 72 | --- 73 | 74 | ## Authors ✍️ 75 | 76 | I'm Dr. Milaan Parmar and I have written this tutorial. If you think you can add/correct/edit and enhance this tutorial you are most welcome🙏 77 | 78 | See [github's contributors page](https://github.com/milaan9/Python_Computer_Vision_from_Scratch/graphs/contributors) for details. 79 | 80 | If you have trouble with this tutorial please tell me about it by [Create an issue on GitHub](https://github.com/milaan9/Python_Computer_Vision_from_Scratch/issues/new). and I'll make this tutorial better. This is probably the best choice if you had trouble following the tutorial, and something in it should be explained better. You will be asked to create a GitHub account if you don't already have one. 81 | 82 | If you like this tutorial, please [give it a ⭐ star](https://github.com/milaan9/Python_Computer_Vision_from_Scratch). 83 | 84 | --- 85 | 86 | ## Licence 📜 87 | 88 | You may use this tutorial freely at your own risk. See [LICENSE](./LICENSE). 89 | -------------------------------------------------------------------------------- /05_Hough_Line_Detection/Hough_Lines.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "### Hough Lines" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 1, 13 | "metadata": { 14 | "collapsed": true 15 | }, 16 | "outputs": [], 17 | "source": [ 18 | "%matplotlib inline\n", 19 | "import cv2\n", 20 | "import matplotlib.pyplot as plt\n", 21 | "import matplotlib.colors\n", 22 | "import numpy as np\n", 23 | "from PIL import Image\n", 24 | "from skimage import data\n", 25 | "import scipy\n", 26 | "import math\n", 27 | "from scipy.ndimage import measurements\n", 28 | "from skimage import data\n", 29 | "from ipywidgets import interact, fixed, FloatSlider, IntSlider,FloatRangeSlider, Label" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": 2, 35 | "metadata": { 36 | "collapsed": true 37 | }, 38 | "outputs": [], 39 | "source": [ 40 | "def display_line_result(og_img, hough_img, edges):\n", 41 | " \n", 42 | " current_image=data.checkerboard()\n", 43 | " w, h = current_image.shape\n", 44 | " output_image = np.empty((w, h, 3))\n", 45 | " edges = cv2.Canny(current_image,50,150,apertureSize =3)\n", 46 | " output_image[:, :, 2] = output_image[:, :, 1] = output_image[:, :, 0] = current_image/255.\n", 47 | " lines = cv2.HoughLines(edges,1,np.pi/180,120)\n", 48 | " max_size=max(w,h)**2\n", 49 | " for rho_theta in lines:\n", 50 | " rho=rho_theta[0][0]\n", 51 | " theta=rho_theta[0][1]\n", 52 | " a = np.cos(theta)\n", 53 | " b = np.sin(theta)\n", 54 | " x0 = a*rho\n", 55 | " y0 = b*rho\n", 56 | " x1 = int(x0 + max_size*(-b))\n", 57 | " y1 = int(y0 + max_size*(a))\n", 58 | " x2 = int(x0 - max_size*(-b))\n", 59 | " y2 = int(y0 - max_size*(a))\n", 60 | " cv2.line(output_image,(x1,y1),(x2,y2),(1,0,0),1)\n", 61 | " \n", 62 | " \n", 63 | " fig2, axes_array = plt.subplots(1, 4)\n", 64 | " fig2.set_size_inches(9,3)\n", 65 | " image_plot = axes_array[0].imshow(og_img,cmap=plt.cm.gray) \n", 66 | " axes_array[0].axis('off')\n", 67 | " axes_array[0].set(title='Original Image')\n", 68 | " image_plot = axes_array[1].imshow(edges,cmap=plt.cm.gray)\n", 69 | " axes_array[1].axis('off')\n", 70 | " axes_array[1].set(title='Edged Image')\n", 71 | " image_plot = axes_array[2].imshow(hough_img)\n", 72 | " axes_array[2].axis('off')\n", 73 | " axes_array[2].set(title='Hough Lines Image')\n", 74 | " image_plot = axes_array[3].imshow(output_image)\n", 75 | " axes_array[3].axis('off')\n", 76 | " axes_array[3].set(title='Hough Lines Open CV')\n", 77 | " plt.show()\n", 78 | " return" 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "execution_count": 3, 84 | "metadata": { 85 | "collapsed": true 86 | }, 87 | "outputs": [], 88 | "source": [ 89 | "def get_canny(og_img):\n", 90 | " edged_image = cv2.Canny(og_img,50,150,apertureSize = 3)#current_image=data.checkerboard()\n", 91 | " return edged_image" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": 4, 97 | "metadata": {}, 98 | "outputs": [ 99 | { 100 | "name": "stderr", 101 | "output_type": "stream", 102 | "text": [ 103 | "C:\\Anaconda3\\lib\\site-packages\\traitlets\\traitlets.py:567: FutureWarning: comparison to `None` will result in an elementwise object comparison in the future.\n", 104 | " silent = bool(old_value == new_value)\n" 105 | ] 106 | }, 107 | { 108 | "data": { 109 | "application/vnd.jupyter.widget-view+json": { 110 | "model_id": "e1431d81a7c14934b8161fed50f87db8" 111 | } 112 | }, 113 | "metadata": {}, 114 | "output_type": "display_data" 115 | }, 116 | { 117 | "data": { 118 | "text/plain": [ 119 | "" 120 | ] 121 | }, 122 | "execution_count": 4, 123 | "metadata": {}, 124 | "output_type": "execute_result" 125 | } 126 | ], 127 | "source": [ 128 | "def hough_lines(og_img,rho_resolution,theta_resolution,threshold):\n", 129 | " rho_theta_values = []\n", 130 | " width, height = og_img.shape\n", 131 | " hough_img = np.empty((width, height, 3))\n", 132 | " hough_img[:, :, 2] = hough_img[:, :, 1] = hough_img[:, :, 0] = og_img/255.\n", 133 | " \n", 134 | " digonal = math.sqrt(width*width + height*height)\n", 135 | " max_size=max(width,height)**2\n", 136 | " \n", 137 | " thetas = np.linspace(0,180,theta_resolution+1)\n", 138 | " rhos = np.linspace(-digonal,digonal,rho_resolution+1)\n", 139 | " \n", 140 | " acc = np.zeros((rho_resolution+1,theta_resolution+1))\n", 141 | "\n", 142 | " for x_index in range(0, width):\n", 143 | " for y_index in range(0, height):\n", 144 | " if edges[x_index][y_index] > 0:\n", 145 | " for t_index in range(0, len(thetas)):\n", 146 | " rho = x_index * math.cos(thetas[t_index]) + y_index * math.sin(thetas[t_index])\n", 147 | " for r_index in range(0, len(rhos)):\n", 148 | " if rhos[r_index]>rho:\n", 149 | " break\n", 150 | " acc[r_index][t_index] += 1\n", 151 | " \n", 152 | " for rho_value in range(0, len(rhos)):\n", 153 | " for t_value in range(0, len(thetas)):\n", 154 | " if acc[rho_value][t_value] >= threshold:\n", 155 | " rho_theta_values.append([rhos[rho_value], thetas[t_value]])\n", 156 | "\n", 157 | " \n", 158 | " for rho_theta in rho_theta_values:\n", 159 | " rho=rho_theta[0]\n", 160 | " theta=rho_theta[1]\n", 161 | " a = np.cos(theta)\n", 162 | " b = np.sin(theta)\n", 163 | " x0 = a*rho\n", 164 | " y0 = b*rho\n", 165 | " x1 = int(x0 + max_size*(-b))\n", 166 | " y1 = int(y0 + max_size*(a))\n", 167 | " x2 = int(x0 - max_size*(-b))\n", 168 | " y2 = int(y0 - max_size*(a))\n", 169 | " cv2.line(hough_img,(x1,y1),(x2,y2),(1,0,0),1)\n", 170 | " \n", 171 | " display_line_result(og_img, hough_img, edges)\n", 172 | " return\n", 173 | " \n", 174 | "og_img = data.checkerboard()\n", 175 | "edges = get_canny(og_img)\n", 176 | "\n", 177 | "interact(hough_lines,\n", 178 | " og_img = fixed(og_img),\n", 179 | " rho_resolution=IntSlider(min=10, max=1000, step=1,value=150,continuous_update=False),\n", 180 | " theta_resolution=IntSlider(min=10, max=1000, step=1,value=360,continuous_update=False),\n", 181 | " threshold=IntSlider(min=5, max=1000, step=1,value=180,continuous_update=False)) " 182 | ] 183 | } 184 | ], 185 | "metadata": { 186 | "kernelspec": { 187 | "display_name": "Python [Root]", 188 | "language": "python", 189 | "name": "Python [Root]" 190 | }, 191 | "language_info": { 192 | "codemirror_mode": { 193 | "name": "ipython", 194 | "version": 3 195 | }, 196 | "file_extension": ".py", 197 | "mimetype": "text/x-python", 198 | "name": "python", 199 | "nbconvert_exporter": "python", 200 | "pygments_lexer": "ipython3", 201 | "version": "3.5.2" 202 | } 203 | }, 204 | "nbformat": 4, 205 | "nbformat_minor": 1 206 | } 207 | -------------------------------------------------------------------------------- /01_Dynamic_Time_Warping/Dynamic_Time_Warping.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Dynamic Time Warping (DTW)\n", 8 | "This notebook describes the DTW concepts.\n" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "metadata": {}, 14 | "source": [ 15 | "## Time Series\n", 16 | "* A time series is a collection of observations made sequentially.\n", 17 | "* Time series occur in different fields such as medical, scientific and businesses domains.\n", 18 | "* Finding the similarity between two time series is useful for clustering and classification.\n", 19 | "\n", 20 | "\n", 21 | "\n", 22 | "## Dynamic Time Warping (DTW)\n", 23 | "Dynamic Time Warping (DTW) is an algorithm for measuring similarity between two sequences which may not have the same length.\n", 24 | "\n", 25 | "\n", 26 | "\n", 27 | "\n", 28 | "In general, the DTW maps each element in the first sequence to an element in the second series. Assuming that a distance function is defined for each pair of points, the goal is to find a mapping that minimizes the total distance between all the points.\n" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": 3, 34 | "metadata": { 35 | "scrolled": false 36 | }, 37 | "outputs": [ 38 | { 39 | "name": "stdout", 40 | "output_type": "stream", 41 | "text": [ 42 | "Automatic pdb calling has been turned OFF\n" 43 | ] 44 | }, 45 | { 46 | "data": { 47 | "application/vnd.jupyter.widget-view+json": { 48 | "model_id": "d67579872ce3424eada3f6e648442cbb" 49 | } 50 | }, 51 | "metadata": {}, 52 | "output_type": "display_data" 53 | } 54 | ], 55 | "source": [ 56 | "try:\n", 57 | " if __IPYTHON__:\n", 58 | " from IPython import get_ipython\n", 59 | "\n", 60 | " get_ipython().magic('matplotlib inline')\n", 61 | " from ipython_utilities import *\n", 62 | " from ipywidgets import interact, fixed, FloatSlider, IntSlider, Label, Checkbox, FloatRangeSlider\n", 63 | " from IPython.display import display\n", 64 | "\n", 65 | " in_ipython_flag = True\n", 66 | "except:\n", 67 | " in_ipython_flag = False\n", 68 | "import cv2 as cv\n", 69 | "from matplotlib import pyplot as plt\n", 70 | "import numpy as np\n", 71 | "from PIL import Image\n", 72 | "from ipywidgets import interact, fixed, FloatSlider, IntSlider, Label, Checkbox, FloatRangeSlider\n", 73 | "\n", 74 | "%matplotlib inline\n", 75 | "%pdb\n", 76 | "\n", 77 | "def display_two_sequences(n1,n2):\n", 78 | " index1 = np.linspace(0,15,n1)\n", 79 | " index2 = np.linspace(0,15,n2)\n", 80 | " A = 5*np.sin(index1)\n", 81 | " B = 3*np.sin(index2 + 1)\n", 82 | " # s1 = [1, 2, 3, 4]\n", 83 | " # s2 = [2, 3, 5, 6, 8]\n", 84 | " # ob_dtw = cl_dtw()\n", 85 | " # distance,_ = ob_dtw.calculate_dtw_distance(s1, s2)\n", 86 | "\n", 87 | " fig = plt.figure(figsize=(12,4))\n", 88 | " plt.plot(index1, A, '-ro', label='A')\n", 89 | " plt.plot(index2, B, '-bo' ,label='B')\n", 90 | " plt.ylabel('value')\n", 91 | " plt.xlabel('index')\n", 92 | " plt.legend()\n", 93 | "\n", 94 | " plt.show()\n", 95 | " plt.pause(0.001)\n", 96 | " \n", 97 | "interact(display_two_sequences,\n", 98 | " n1=IntSlider(min=0, \n", 99 | " max=100, step=1,value=5,\n", 100 | " description='# of points in sequence 1',\n", 101 | " continuous_update=True),\n", 102 | " n2=IntSlider(min=0, \n", 103 | " max=100, step=1,value=7,\n", 104 | " description='# of points in sequence 2',\n", 105 | " continuous_update=True));\n", 106 | "\n", 107 | "# arrange_widgets_in_grid(controls)\n" 108 | ] 109 | }, 110 | { 111 | "cell_type": "markdown", 112 | "metadata": {}, 113 | "source": [ 114 | "Consider the two sequences $A=\\{a_1, a_2, ... , a_M\\}$ and $B=\\{b_1, b_2, ... , b_N\\}$ as shown above. Where $a_k$ is the $k_{th}$ sample point in the sequence $A$ and $b_k$ is the $k_{th}$ sample point in the sequence $B$. To find the similarity of these two sequences we need to calculate the total distance between the two sequences. To calculate the total distance we can connects each point in sequence $A$ to a point in sequence $B$ and accumulate the distances between the corresponding points. Since there are so many different possibilities for connecting different points, then the question is what is the best possible arrangement which results in the minimum total distance? \n", 115 | "In order for the similarity measure to be meaningful we need to impose some constraints on how the points on the two sequence should be connected:\n", 116 | "* **Boundary conditions:** the first points should be connected to each other and the last points should be connected to each point.\n", 117 | "* **Monotonicity:** The alignment can not go backward. \n", 118 | "* **Continuity:** The alignment can not skip an element.\n", 119 | "* **Warping window:** The same point (feature) should not be repeated too many times.\n", 120 | "\n", 121 | "### Path\n", 122 | "A path $P$ is defined as an ordered set of 2-tuples:\n", 123 | "\n", 124 | "$$\\large P=p_1,p_2, .....p_q$$\n", 125 | "$$\\large p_k=(i_k,j_k)$$\n", 126 | "\n", 127 | "where $q$ is the number of connections (correspondences) and $i_k$ and $j_k$ are the indexes of the connecting elements. $P_s$ is called a \"Warping\" function.\n", 128 | "\n", 129 | "For example $P=(1,1), (1,2), (2,3), ... $ means:\n", 130 | "* Point 1 in sequence A is connected to point 1 in sequence B\n", 131 | "* Point 1 in sequence A is connected to point 2 in sequence B\n", 132 | "* Point 2 in sequence A is connected to point 3 in sequence B\n", 133 | "* ...\n", 134 | "\n", 135 | "\n", 136 | "\n", 137 | "\n", 138 | "A path can be shown on a grid of M rows by N columns. The image below shows two possible paths. Notice that there are many possible paths for connecting elements of the sequence A to elements of the sequence B without violating any the constraints. The cost of each path is the accumulated distance between the corresponding points. **The goal of the DTW algorithm is to find the best path which minimizes the total cost.**\n", 139 | "\n" 140 | ] 141 | }, 142 | { 143 | "cell_type": "markdown", 144 | "metadata": {}, 145 | "source": [ 146 | "### Finding the Best Path\n", 147 | "To find the best path:\n", 148 | "* Set an M by N matrix G\n", 149 | "* Set $G\\left[1,1\\right]=d(1,1)$ where $d(i,j)$ is the distance between elements i and j in the sequences respectively.\n", 150 | "* Calculate each element of the the matrix G as:\n", 151 | "\n", 152 | "$$\\large G\\left[i,j\\right]=d(i,j)+min(G\\left[i,j-1\\right],G\\left[i-1,j\\right],G\\left[i-1,j-1\\right])$$\n", 153 | "\n", 154 | "* Total distance will be $D(A,B)=G\\left[M,N\\right]$\n", 155 | "\n" 156 | ] 157 | }, 158 | { 159 | "cell_type": "code", 160 | "execution_count": 4, 161 | "metadata": {}, 162 | "outputs": [ 163 | { 164 | "data": { 165 | "application/vnd.jupyter.widget-view+json": { 166 | "model_id": "1bfda76d79aa402f8f904b6ff209424d" 167 | } 168 | }, 169 | "metadata": {}, 170 | "output_type": "display_data" 171 | } 172 | ], 173 | "source": [ 174 | "def dtw(s1, s2, window=3):\n", 175 | " grid = np.inf*np.ones((len(s1), len(s2)))\n", 176 | " # grid[0, :] = abs(s1[0] - s2)\n", 177 | " for i in range(window+1):\n", 178 | " grid[0, i] = abs(s1[0] - s2[i])\n", 179 | " for j in range(window+1):\n", 180 | " grid[j, 0] = abs(s2[0] - s1[j])\n", 181 | " \n", 182 | " for i in range(1, len(s1)):\n", 183 | " for j in range(1, len(s2)):\n", 184 | " if abs(i-j) > window:\n", 185 | " continue\n", 186 | " grid[i, j] = abs(s1[i] - s2[j]) + min(grid[i - 1, j], grid[i, j-1], grid[i-1, j-1])\n", 187 | " \n", 188 | " \n", 189 | " print(grid)\n", 190 | " print(grid[-1, -1])\n", 191 | " \n", 192 | "def display_two_sequences(n1,n2):\n", 193 | " index1 = np.linspace(0,15,n1)\n", 194 | " index2 = np.linspace(0,15,n2)\n", 195 | " A = [5, 6, 9, 2, 6]*2\n", 196 | " B = [5, 7, 2, 6, 9 , 2]*2\n", 197 | " #A = 5*np.sin(index1)\n", 198 | " #B = 3*np.sin(index2 + 1)\n", 199 | " # s1 = [1, 2, 3, 4]\n", 200 | " # s2 = [2, 3, 5, 6, 8]\n", 201 | " # ob_dtw = cl_dtw()\n", 202 | " # distance,_ = ob_dtw.calculate_dtw_distance(s1, s2)\n", 203 | " print(A)\n", 204 | " print(B)\n", 205 | " \n", 206 | " dtw(A, B)\n", 207 | "# fig = plt.figure(figsize=(12,4))\n", 208 | "# plt.plot(index1, A, '-ro', label='A')\n", 209 | "# plt.plot(index2, B, '-bo' ,label='B')\n", 210 | "# plt.ylabel('value')\n", 211 | "# plt.xlabel('index')\n", 212 | "# plt.legend()\n", 213 | "\n", 214 | "# plt.show()\n", 215 | "# plt.pause(0.001)\n", 216 | "controls = interact(display_two_sequences,\n", 217 | " n1=IntSlider(min=0, \n", 218 | " max=100, step=1,value=5,\n", 219 | " description='# of points in sequence 1',\n", 220 | " continuous_update=True),\n", 221 | " n2=IntSlider(min=0, \n", 222 | " max=100, step=1,value=7,\n", 223 | " description='# of points in sequence 2',\n", 224 | " continuous_update=True));\n", 225 | "\n", 226 | "# arrange_widgets_in_grid(controls)\n" 227 | ] 228 | }, 229 | { 230 | "cell_type": "code", 231 | "execution_count": null, 232 | "metadata": { 233 | "collapsed": true 234 | }, 235 | "outputs": [], 236 | "source": [] 237 | }, 238 | { 239 | "cell_type": "markdown", 240 | "metadata": {}, 241 | "source": [ 242 | "### Warping Window\n", 243 | "In order to gurantee that the alignment does not get stuck in one element a warping window is defined. The warping window limits the difference between the indexes of the two sequence. In cases where the number of elements in both sequences are equal, the warping window forces the path not to wander too far from the diagnoal.\n", 244 | "\n", 245 | "\n", 246 | "In a given path the warping window constraints can be imposed by limiting $\\left| {i_k - j_k} \\right| \\le r,r > 0$\n", 247 | "\n", 248 | "\n", 249 | "\n" 250 | ] 251 | }, 252 | { 253 | "cell_type": "markdown", 254 | "metadata": {}, 255 | "source": [ 256 | "### Slope Constraints\n", 257 | "In order to prevent that a very short section of one sequence match a very long section of another, a slope constraint is imposed on the path.\n", 258 | "\n", 259 | "\n", 260 | "$$\\large {{\\left( {{j_{k + s}} - {j_k}} \\right)} \\over {\\left( {{i_{k + s}} - {i_k}} \\right)}} \\le {s_h}$$\n", 261 | "\n", 262 | "and \n", 263 | "\n", 264 | "$$\\large {{\\left( {{i_{k + s}} - {i_k}} \\right)} \\over {\\left( {{j_{k + s}} - {j_k}} \\right)}} \\le {s_v}$$\n", 265 | "\n", 266 | "where $S_h>0$ and $S_v>0$ are the limiting slope constants.\n" 267 | ] 268 | }, 269 | { 270 | "cell_type": "markdown", 271 | "metadata": {}, 272 | "source": [ 273 | "### Time Normalized Distance Measure\n", 274 | "The time normalized distance between two sequences $A$ and $B$ for a particular path $P$ is defined as:\n", 275 | "\n", 276 | "$$\\large D(A,B)= {{{\\sum\\limits_{k = 1}^q {d({p_k}) \\cdot {w_k}} } \\over {\\sum\\limits_{k = 1}^q {{w_k}} }}} $$\n", 277 | "\n", 278 | "$$\\large p_k=(i_k,j_k)$$\n", 279 | "\n", 280 | "where $d(p_k)$ is the distance between element $i_k$ in the sequence A and element $j_k$ in the sequence B.\n", 281 | "\n", 282 | "$w_k$ is the weighting coefficient for the connection k. \n", 283 | "\n", 284 | "The best path $P^*$ is found by minimizing the $D(A,B)$\n", 285 | "\n", 286 | "$$\\large {P^*} = \\mathop {argmin }\\limits_P (D(A,B))$$\n", 287 | "\n", 288 | "\n", 289 | "The term $\\sum\\limits_{k = 1}^q {{w_k}} $ in the denominator of the $D(A,B)$ complicates the optimization of the best path because it dependes on the length of the path. It is desirable to find some weighting coefficients that are independent of the path $P$. For example if we define \n", 290 | "$$\\large w_k= (i_k-i_{k-1})+(j_k-j_{k-1})$$\n", 291 | "\n", 292 | "then \n", 293 | "$$\\large \\sum\\limits_{k = 1}^q {{w_k}}=M+N=C$$\n", 294 | "\n", 295 | "This means that the denominator of the $D(A,B)$ is a constant\n", 296 | "\n", 297 | "$$\\large D(A,B)={1 \\over C}\\mathop {\\mathop {argmin }\\limits_P \\left[ {\\sum\\limits_{s = 1}^k {d({p_s}) \\cdot {w_s}} } \\right]}\\limits_{} $$ \n", 298 | "\n", 299 | "A an alternative we can define \n", 300 | "$\\large w_k= (i_k-i_{k-1})$ which implies $\\large \\sum\\limits_{k = 1}^q {{w_k}}=M=C$\n", 301 | "\n", 302 | "or $\\large w_k= (j_k-j_{k-1})$ which implies $\\large \\sum\\limits_{k = 1}^q {{w_k}}=N=C$\n", 303 | "\n", 304 | "The algorithm for finding the best path with time normalization $w_k=(ik−ik−1)+(jk−jk−1)$ will be:\n", 305 | "\n", 306 | "* Set an M by N matrix G\n", 307 | "* Set $G\\left[1,1\\right]=2d(1,1)$ where $d(i,j)$ is the distance between elements i and j in the sequences respectively.\n", 308 | "* Calculate each element of the the matrix G as:\n", 309 | "\n", 310 | "$$\\large G\\left[i,j\\right]=min(G\\left[i,j-1\\right],G\\left[i-1,j\\right],2d(i,j)G\\left[i-1,j-1\\right])$$\n", 311 | "* Total distance will be:\n", 312 | "$$\\large D(A,B)={{G\\left[M,N\\right]}\\over {(N+M)}}$$\n" 313 | ] 314 | } 315 | ], 316 | "metadata": { 317 | "anaconda-cloud": {}, 318 | "kernelspec": { 319 | "display_name": "Python [Root]", 320 | "language": "python", 321 | "name": "Python [Root]" 322 | }, 323 | "language_info": { 324 | "codemirror_mode": { 325 | "name": "ipython", 326 | "version": 3 327 | }, 328 | "file_extension": ".py", 329 | "mimetype": "text/x-python", 330 | "name": "python", 331 | "nbconvert_exporter": "python", 332 | "pygments_lexer": "ipython3", 333 | "version": "3.5.2" 334 | }, 335 | "widgets": { 336 | "state": { 337 | "0555dd1618ac47b3879d19b0892a25a2": { 338 | "views": [ 339 | { 340 | "cell_index": 2 341 | } 342 | ] 343 | }, 344 | "47a1a1eb88fb4c3d914c19a8c7d83596": { 345 | "views": [ 346 | { 347 | "cell_index": 5 348 | } 349 | ] 350 | } 351 | }, 352 | "version": "1.2.0" 353 | } 354 | }, 355 | "nbformat": 4, 356 | "nbformat_minor": 1 357 | } 358 | -------------------------------------------------------------------------------- /06_Feature_Detection/Feature_Detection.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Feature Detection\n", 8 | "This notebook explains the basic concepts of feature detectors and feature descriptors in the field of image processing and computer vision." 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "metadata": {}, 14 | "source": [ 15 | "## What are features in an image?\n", 16 | "A feature is a piece of information that describes an image or part of an image. For example edges and corners are features which can be detected in an image. " 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": {}, 22 | "source": [ 23 | "## Feature points (key points)\n", 24 | "A feature point, or a key point, on an image is a point which has unique and identifiable properties. These unique properties can be used to match the key point to another key point in a different image. For example an edge point or a corner point in an image can be considered as feature points. Edge points suffer from aperture problem because an edge point in one image can not be uniquely matched to an edge point in another image.\n", 25 | "Corner points are better feature points because it is easier to match a corner point in one image to a corner point in another image." 26 | ] 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "metadata": {}, 31 | "source": [ 32 | "## What is a feature detector?\n", 33 | "\n", 34 | "Feature detection is a general term which involves reducing the amount of information required to describe a set of data. In image processing and computer vision a feature detector is a process that detects the presence of certain attribute or aspect of the visual scene. For example an edge is considered a feature in an image and edge detection is one kind of feature detectors. \n", 35 | "\n", 36 | "There are generally two methods for feature detection and presentation, global features and local features. In global methods features are extracted from the entire image and the original image is represented by a set of global features, called feature vector. The feature vectors usually have lower dimensions than the original image. In contrast, in the local feature presentation, the features are extracted from a local neighborhood around **interest points** or **key points**. \n", 37 | "\n", 38 | "* Examples of global feature presentation:\n", 39 | " * Principal Component Analysis (PCA)\n", 40 | " * Independent Component Analysis (ICA)\n", 41 | " * Linear Discriminant Analysis (LDA)\n", 42 | " * ...\n", 43 | "* Examples of local feature presentation:\n", 44 | " * Edges\n", 45 | " * Corners\n", 46 | " * Blobs\n", 47 | " * ...\n", 48 | " \n", 49 | "** Note:**\n", 50 | "Feature detection is not the same as feature selection. \n", 51 | "Feature detectors are processes that identify features in local neighborhood by processing the information surrounding a pixel. In other words, in feature detection the information in the original data is combined (transformed) into a lower dimensional space. However, in feature selection a subset of existing data or features is selected without transformation.\n" 52 | ] 53 | }, 54 | { 55 | "cell_type": "markdown", 56 | "metadata": {}, 57 | "source": [ 58 | "## Characteristics of good feature detectors\n", 59 | "\n", 60 | "Good features in an image should be as unique as possible and they should allow efficient matching of features between images. A good feature detector should have the following properties:\n", 61 | "* **Invariance:** A ideal feature detector should be invariant to scaling, rotation, translation, perspective projection, image intensity, and photometric deformations.\n", 62 | "* **Robustness:** The feature detector should be able to detect the same feature independent of noise in the image intensity. \n", 63 | "* **Accuracy:** The feature detector should accurately determine the location of a feature.\n", 64 | "* **Efficiency:** The feature detection algorithm should be computationally efficient.\n", 65 | "* **Quantity:** The ideal feature detector should be able to detect all of the features in the image." 66 | ] 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "metadata": {}, 71 | "source": [ 72 | "## Harris corner detector\n", 73 | "The basic idea of Harris corner detector is that if we look through a small window (small kernel) at a particular location in the image and multiply each pixel by the corresponding value in the kernel and sum all the values then:\n", 74 | "* if the kernel is located at a flat region of an image then moving it in any direction does not change the result.\n", 75 | "* If the kernel is located on an edge then moving the kernel parallel to an edge then the result will not change but if move the kernel perpendicular to an edge then the result will change.\n", 76 | "* If the kernel is located on a corner (intersection of two edges), then moving the kernel in any direction will change the result. We can capture this concept mathematically:\n", 77 | "$$\\large E(u,v) = \\sum\\limits_{x,y} {w(x,y){{\\left[ {f(x + {\\Delta x},y + {\\Delta y}) - f(x,y)} \\right]}^2}} $$\n", 78 | "\n", 79 | "\n", 80 | "where $w(x,y)$ is the kernel (window) and $f(x,y)$ is the image intensity at pixel location $(x,y)$ and ${\\Delta x}$ and ${\\Delta y}$ are small movements in $x$ and $y$ directions.\n", 81 | "\n", 82 | "If we expand the above equation by using the first order Taylor series then we get:\n", 83 | "\n", 84 | "$$\\large E(u,v) = \\sum\\limits_{x,y} {w(x,y){{\\left[ {f({x},{y}) + \\left[ {\\begin{array}{*{20}{c}}\n", 85 | "{{\\textstyle{{\\partial f({x},{y})} \\over {\\partial x}}}}&{{\\textstyle{{\\partial f({x},{y})} \\over {\\partial y}}}}\n", 86 | "\\end{array}} \\right]\\left[ {\\begin{array}{*{20}{c}}\n", 87 | "{\\Delta x}\\\\\n", 88 | "{\\Delta y}\n", 89 | "\\end{array}} \\right] - f(x,y)} \\right]}^2}} $$\n", 90 | "\n", 91 | "----\n", 92 | "$$\\large E(u,v) = \\sum\\limits_{x,y} {w(x,y){{{\\left[ {\\begin{array}{*{20}{c}}\n", 93 | "{\\Delta x}&{\\Delta y}\n", 94 | "\\end{array}} \\right]\\left( {\\left[ {\\begin{array}{*{20}{c}}\n", 95 | "{{\\textstyle{{\\partial f({x_i},{y_i})} \\over {\\partial x}}}}\\\\\n", 96 | "{{\\textstyle{{\\partial f({x_i},{y_i})} \\over {\\partial y}}}}\n", 97 | "\\end{array}} \\right]\\left[ {\\begin{array}{*{20}{c}}\n", 98 | "{{\\textstyle{{\\partial f({x_i},{y_i})} \\over {\\partial x}}}}&{{\\textstyle{{\\partial f({x_i},{y_i})} \\over {\\partial y}}}}\n", 99 | "\\end{array}} \\right]} \\right)\\left[ {\\begin{array}{*{20}{c}}\n", 100 | "{\\Delta x}\\\\\n", 101 | "{\\Delta y}\n", 102 | "\\end{array}} \\right]}}}} $$\n", 103 | "\n", 104 | "----\n", 105 | "$$\\large E(u,v) = \\left[ {\\begin{array}{*{20}{c}}\n", 106 | "{\\Delta x}&{\\Delta y}\n", 107 | "\\end{array}} \\right]\\sum\\limits_{x,y} {w(x,y){{{\\left( {\\left[ {\\begin{array}{*{20}{c}}\n", 108 | "{{\\textstyle{{\\partial f({x_i},{y_i})} \\over {\\partial x}}}}\\\\\n", 109 | "{{\\textstyle{{\\partial f({x_i},{y_i})} \\over {\\partial y}}}}\n", 110 | "\\end{array}} \\right]\\left[ {\\begin{array}{*{20}{c}}\n", 111 | "{{\\textstyle{{\\partial f({x_i},{y_i})} \\over {\\partial x}}}}&{{\\textstyle{{\\partial f({x_i},{y_i})} \\over {\\partial y}}}}\n", 112 | "\\end{array}} \\right]} \\right)\\left[ {\\begin{array}{*{20}{c}}\n", 113 | "{\\Delta x}\\\\\n", 114 | "{\\Delta y}\n", 115 | "\\end{array}} \\right]}}}} $$\n", 116 | "\n", 117 | "----\n", 118 | "$$\\large E(u,v) = \\left[ {\\begin{array}{*{20}{c}}\n", 119 | "{\\Delta x}&{\\Delta y}\n", 120 | "\\end{array}} \\right]\\sum\\limits_{x,y} {w(x,y){{{\n", 121 | "\\left[ {\\begin{array}{*{20}{c}}\n", 122 | "{ {{{\\left( {{\\textstyle{{\\partial f({x_i},{y_i})} \\over {\\partial x}}}} \\right)}^2}} }&{ {{\\textstyle{{\\partial f({x_i},{y_i})} \\over {\\partial x}}}{\\textstyle{{\\partial f({x_i},{y_i})} \\over {\\partial y}}}} }\\\\\n", 123 | "{ {{\\textstyle{{\\partial f({x_i},{y_i})} \\over {\\partial x}}}{\\textstyle{{\\partial f({x_i},{y_i})} \\over {\\partial y}}}} }&{{{{\\left( {{\\textstyle{{\\partial f({x_i},{y_i})} \\over {\\partial y}}}} \\right)}^2}} }\n", 124 | "\\end{array}} \\right]\n", 125 | "\\left[ {\\begin{array}{*{20}{c}}\n", 126 | "{\\Delta x}\\\\\n", 127 | "{\\Delta y}\n", 128 | "\\end{array}} \\right]}}}} $$\n", 129 | "\n", 130 | "----\n", 131 | "$$\\large E(u,v) = \\left[ {\\begin{array}{*{20}{c}}\n", 132 | "{\\Delta x}&{\\Delta y}\n", 133 | "\\end{array}} \\right] A\\left[ {\\begin{array}{*{20}{c}}\n", 134 | "{\\Delta x}\\\\\n", 135 | "{\\Delta y}\n", 136 | "\\end{array}} \\right] $$\n", 137 | " where \n", 138 | "$$\\large A = \\sum\\limits_{x,y} {w(x,y)\\left[ {\\begin{array}{*{20}{c}}\n", 139 | "{I_x^2}&{{I_x}{I_y}}\\\\\n", 140 | "{{I_x}{I_y}}&{I_y^2}\n", 141 | "\\end{array}} \\right]} $$\n", 142 | "\n", 143 | "Matrix $A$ is called the Harris matrix. This matrix is symmetric and Positive semi-definite. The Eigen values of this matrix which are λ1 and λ2 (λ1 >= λ2) , determine the sensitivity of the matrix $A$ to small movements.\n", 144 | "* If Both λ1 and λ2 are small then that means that there are no edges or corner in that position and the corresponding point is in a flat region.\n", 145 | "* If λ1 is large but λ2 is small then that means that the point is on an edge (no corner).\n", 146 | "* If both λ1 and λ2 are large then the point is on a corner \n", 147 | "\n", 148 | "There is another alternative to Eigenvalues to measure the response of the Harris detector:\n", 149 | "\n", 150 | "$$R({{\\bf{A}}}) = \\det (A) - \\kappa {\\rm{trac}}{{\\rm{e}}^2}({\\bf{A}})=λ1λ2-\\alpha(λ1+λ2)$$\n", 151 | "\n", 152 | "where $R({{\\bf{A}}})$ is the response function. The value of the constant $\\alpha$ is usually between 0.04 and 0.15\n" 153 | ] 154 | }, 155 | { 156 | "cell_type": "markdown", 157 | "metadata": {}, 158 | "source": [ 159 | "## Steps for Harris detector\n", 160 | "\n", 161 | "* Filter the image with a Gaussian\n", 162 | "* Estimate gradients in x and y directions. (This step and the last one could be performed together by convolving the image with the derivative of Gaussians in x and y directions.\n", 163 | "* Calculate $I_x^2$ , $I_y^2$ , and $I_x I_y$\n", 164 | "* Smooth the three calculated images with a Gaussian\n", 165 | "* For each pixel calculate the matrix A on a local neighborhood \n", 166 | "* Compute the response function R(A)\n", 167 | "* Choose the best candidates for corners by selecting thresholds on the response function R(A) \n", 168 | "* Apply non-maximal suppression\n" 169 | ] 170 | }, 171 | { 172 | "cell_type": "code", 173 | "execution_count": 4, 174 | "metadata": { 175 | "collapsed": true 176 | }, 177 | "outputs": [], 178 | "source": [ 179 | "# Import the required modules\n", 180 | "import matplotlib.pyplot as plt\n", 181 | "import matplotlib.colors\n", 182 | "import numpy as np\n", 183 | "from IPython.display import display\n", 184 | "from PIL import Image\n", 185 | "from skimage import data\n", 186 | "import scipy\n", 187 | "import scipy.ndimage\n", 188 | "# import ipywidgets as widgets\n", 189 | "from ipywidgets import HBox, VBox, interact,interactive, fixed, FloatSlider, IntSlider, Label, Checkbox, FloatRangeSlider\n", 190 | "import cv2 as cv\n", 191 | "plt.rcParams['image.interpolation'] = 'none'" 192 | ] 193 | }, 194 | { 195 | "cell_type": "code", 196 | "execution_count": 5, 197 | "metadata": { 198 | "collapsed": true 199 | }, 200 | "outputs": [], 201 | "source": [ 202 | "# This cell is a utility function to arrange the Ipython widgets in a grid.\n", 203 | "from IPython.display import display\n", 204 | "from ipywidgets import Layout,HBox,VBox,interact,interactive, fixed, FloatSlider, IntSlider, Label, Checkbox, FloatRangeSlider\n", 205 | "\n", 206 | "def arrange_widgets_in_grid(widgets_list,number_of_col=2,label_width_percent=50,height_pixels=40):\n", 207 | " \"\"\"\n", 208 | " This function arranges the widgets in a two dimensional grid.\n", 209 | " According to the Ipython widgets documentation: \"You cannot change the width of the internal description field\".\n", 210 | " This means that if the description for a widget, such as a slider, is too long then it can not be properly \n", 211 | " displayed. In order to display a long description it should be put in \"HBox\" widget.\n", 212 | " This function uses combinations of HBox, VBox, and Layout to display the widgets\n", 213 | " in a grid and allow long widget descriptions to be properly displayed.\n", 214 | " Farhad Kamangar\n", 215 | " Feb. 4, 2017\n", 216 | " \"\"\"\n", 217 | " label_layout=Layout(width=\"{0:d}%\".format(int(label_width_percent)), \n", 218 | " height=\"{0:d}px\".format(height_pixels))\n", 219 | " widget_layout=Layout(width=\"{0:d}%\".format(int(100-(label_width_percent))), \n", 220 | " height=\"{0:d}px\".format(height_pixels))\n", 221 | " hbox_layout=Layout(border='2px solid blue',width='100%',\n", 222 | " display='inline-flex',flex_flow='row wrap')\n", 223 | " vbox_layout=Layout(border='2px solid black',width=\"{0:d}%\".format(int(90/number_of_col)),\n", 224 | " display='inline-flex',flex_flow='row wrap')\n", 225 | " column_widgets = [[] for i in range(number_of_col)]\n", 226 | " for k,current_widget in enumerate(widgets_list.children):\n", 227 | " col=k%number_of_col\n", 228 | " current_description=widgets_list.children[k].description\n", 229 | " widgets_list.children[k].description=\"\" \n", 230 | " current_hbox_label=HBox(layout=label_layout)\n", 231 | " current_hbox_label.children=[Label(current_description)]\n", 232 | " current_hbox_widget=HBox(layout=widget_layout)\n", 233 | " current_hbox_widget.children=[widgets_list.children[k]]\n", 234 | " current_hbox = HBox(layout=hbox_layout) \n", 235 | " current_hbox.children=[current_hbox_label,current_hbox_widget]\n", 236 | "\n", 237 | " column_widgets[col].append(current_hbox)\n", 238 | " list_of_vboxes=[]\n", 239 | "\n", 240 | " for k in range(number_of_col):\n", 241 | " current_vbox=VBox(column_widgets[k])\n", 242 | " current_vbox.layout=vbox_layout\n", 243 | " list_of_vboxes.append(current_vbox)\n", 244 | " master_widget=HBox(list_of_vboxes)\n", 245 | " widgets_list.children=(master_widget,)\n", 246 | " display(widgets_list)" 247 | ] 248 | }, 249 | { 250 | "cell_type": "markdown", 251 | "metadata": {}, 252 | "source": [ 253 | "### Calculate gradients" 254 | ] 255 | }, 256 | { 257 | "cell_type": "code", 258 | "execution_count": 6, 259 | "metadata": {}, 260 | "outputs": [ 261 | { 262 | "name": "stderr", 263 | "output_type": "stream", 264 | "text": [ 265 | "C:\\Anaconda3\\lib\\site-packages\\traitlets\\traitlets.py:567: FutureWarning: comparison to `None` will result in an elementwise object comparison in the future.\n", 266 | " silent = bool(old_value == new_value)\n" 267 | ] 268 | }, 269 | { 270 | "data": { 271 | "application/vnd.jupyter.widget-view+json": { 272 | "model_id": "ae5968ad04d84f66b71d9716e5355490" 273 | } 274 | }, 275 | "metadata": {}, 276 | "output_type": "display_data" 277 | } 278 | ], 279 | "source": [ 280 | "from scipy.ndimage import convolve\n", 281 | "# plt.rcParams['image.interpolation'] = 'none'\n", 282 | "def calculate_and_display_harris_corner_detector(original_image,\n", 283 | " gaussian_kernel_size_1=9,\n", 284 | " gaussian_kernel_sigma_1=1,\n", 285 | " gaussian_kernel_size_2=17,\n", 286 | " gaussian_kernel_sigma_2=5.0,\n", 287 | " alpha=0.04, # Recommended value between .04 and .06\n", 288 | " non_maxima_neighborhood_size=7,\n", 289 | " normalized_response_threshold=0.001,\n", 290 | " display_absolute=False):\n", 291 | " horizontal_kernel = np.array([[ 1., 2, 1],[ 0, 0, 0],[-1,-2,-1]])\n", 292 | " vertical_kernel = np.array([[ -1., 0, 1],[ -2, 0, 2],[-1,0,1]])\n", 293 | " # Normalize the kernels\n", 294 | " kernel_sum=abs(np.sum(horizontal_kernel))\n", 295 | " horizontal_kernel= horizontal_kernel/kernel_sum if kernel_sum else horizontal_kernel\n", 296 | " kernel_sum=abs(np.sum(vertical_kernel))\n", 297 | " vertical_kernel= vertical_kernel/kernel_sum if kernel_sum else vertical_kernel\n", 298 | " # GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]])\n", 299 | " smooth_original_image = cv.GaussianBlur(original_image, \n", 300 | " (gaussian_kernel_size_1,gaussian_kernel_size_1), gaussian_kernel_sigma_1)\n", 301 | "\n", 302 | " # calculate the gradients in x direction\n", 303 | " i_x = scipy.ndimage.convolve(smooth_original_image, vertical_kernel)\n", 304 | " # Claculate the gradients in the y direction\n", 305 | " i_y = scipy.ndimage.convolve(smooth_original_image, horizontal_kernel)\n", 306 | " # Calculate the elements of the Harris matrix\n", 307 | " i_xx = i_x* i_x\n", 308 | " i_xy = i_x* i_y\n", 309 | " i_yy = i_y* i_y\n", 310 | "# GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]])\n", 311 | " s_xx = cv.GaussianBlur(i_xx, (gaussian_kernel_size_2,gaussian_kernel_size_2), gaussian_kernel_sigma_2)\n", 312 | " s_xy = cv.GaussianBlur(i_xy, (gaussian_kernel_size_2,gaussian_kernel_size_2), gaussian_kernel_sigma_2)\n", 313 | " s_yy = cv.GaussianBlur(i_yy, (gaussian_kernel_size_2,gaussian_kernel_size_2), gaussian_kernel_sigma_2)\n", 314 | " # Calculate the response of the Harris detector at each point\n", 315 | " det_of_a = (s_xx* s_yy) - (s_xy* s_xy)\n", 316 | " trace_of_a = s_xx + s_yy\n", 317 | " R = det_of_a - alpha*(trace_of_a*trace_of_a)\n", 318 | " thresholded_response=np.copy(R)\n", 319 | " threshold=normalized_response_threshold * np.max(R)\n", 320 | " thresholded_response[R < threshold]=0.0\n", 321 | " # suppress non-maxima points in a neighborhood\n", 322 | " temp_maximas=scipy.ndimage.maximum_filter(thresholded_response, size=non_maxima_neighborhood_size)\n", 323 | " mask=[temp_maximas==thresholded_response] and [R>=threshold]\n", 324 | " output_response=np.zeros(R.shape)\n", 325 | " output_response[mask]=1\n", 326 | " # Display results after each step\n", 327 | " fig1, axes_array = plt.subplots(2, 3)\n", 328 | " fig1.set_size_inches(9,6)\n", 329 | " axes_array=np.ravel(axes_array)\n", 330 | " \n", 331 | " image_plot = axes_array[0].imshow(original_image ,cmap=plt.cm.gray) # Show the original image\n", 332 | " # axes_array[0].axis('off')\n", 333 | " axes_array[0].set(title='Original image')\n", 334 | " if display_absolute:\n", 335 | " image_plot = axes_array[1].imshow(np.abs(i_x),cmap=plt.cm.gray) # Show absolute value of the filtered image\n", 336 | " else:\n", 337 | " image_plot = axes_array[1].imshow(i_x,cmap=plt.cm.gray) # Show the filtered image\n", 338 | " axes_array[1].axis('off')\n", 339 | " axes_array[1].set(title='Horizontal Edges')\n", 340 | " if display_absolute:\n", 341 | " image_plot = axes_array[2].imshow(np.abs(i_y),cmap=plt.cm.gray) \n", 342 | " else:\n", 343 | " image_plot = axes_array[2].imshow(i_y,cmap=plt.cm.gray) \n", 344 | " axes_array[2].axis('off')\n", 345 | " axes_array[2].set(title='Vertical Edges')\n", 346 | " if display_absolute:\n", 347 | " image_plot = axes_array[3].imshow(np.abs(R),cmap=plt.cm.gray) \n", 348 | " else:\n", 349 | " image_plot = axes_array[3].imshow(R,cmap=plt.cm.gray) \n", 350 | " axes_array[3].axis('off')\n", 351 | " axes_array[3].set(title='Harris Response')\n", 352 | " \n", 353 | " image_plot = axes_array[4].imshow(thresholded_response,cmap=plt.cm.gray) \n", 354 | " axes_array[4].axis('off')\n", 355 | " axes_array[4].set(title='Thresholded Response')\n", 356 | " w, h = original_image.shape\n", 357 | " output_image = np.empty((w, h, 3))\n", 358 | " output_image[:, :, 2] = output_image[:, :, 1] = output_image[:, :, 0] = original_image\n", 359 | " # Dilating is not part of Harris corner detection\n", 360 | " # It is done so the red dots on the corners can be seen better\n", 361 | "# output_response = cv.dilate(output_response,None)\n", 362 | " output_image[output_response>0]=[1,0,0]\n", 363 | " image_plot = axes_array[5].imshow(output_image) \n", 364 | "# image_plot = axes_array[5].imshow(output_response,cmap=plt.cm.gray) \n", 365 | " axes_array[5].axis('off')\n", 366 | " axes_array[5].set(title='Corners') \n", 367 | " \n", 368 | " plt.show()\n", 369 | "\n", 370 | "current_image=data.checkerboard()/255.\n", 371 | "# current_image=data.text()/255.\n", 372 | "# image_size=100\n", 373 | "# current_image=np.zeros((image_size,image_size))\n", 374 | "# current_image[int(image_size/4):-int(image_size/4),int(image_size/4):-int(image_size/4)]=1\n", 375 | "# current_image[int(image_size/3):-int(image_size/3),int(image_size/3):-int(image_size/3)]=0\n", 376 | "\n", 377 | "\n", 378 | "controls=interact(calculate_and_display_harris_corner_detector,\n", 379 | " original_image=fixed(current_image),\n", 380 | " gaussian_kernel_size_1=IntSlider(min=3,max=51,step=2,\n", 381 | " value=3,description='Gaussian Kernel Size #1',continuous_update=False),\n", 382 | " gaussian_kernel_sigma_1=FloatSlider(min=0.0, max=10, step=0.01, \n", 383 | " value=1.0,description='Gaussian Sigma #1',continuous_update=False),\n", 384 | " gaussian_kernel_size_2=IntSlider(min=3,max=51,step=2,\n", 385 | " value=3,description='Gaussian Kernel Size #2',continuous_update=False),\n", 386 | " gaussian_kernel_sigma_2=FloatSlider(min=0.0, max=10, step=0.01, \n", 387 | " value=1,description='Gaussian Sigma #2',continuous_update=False),\n", 388 | " alpha=FloatSlider(min=0.01, max=0.5, step=0.01, \n", 389 | " value=0.04,description='Alpha',continuous_update=False), \n", 390 | " non_maxima_neighborhood_size=IntSlider(min=3, max=51, step=2, value=19,\n", 391 | " description='Non-maxima Neighborhood size',continuous_update=False),\n", 392 | " normalized_response_threshold=FloatSlider(min=0.0, max=1, step=0.001,readout_format='.4f', \n", 393 | " value=0.002,description='Response Threshold',continuous_update=False),\n", 394 | " display_absolute=Checkbox(value=False,description='Display Absolute Values'))\n", 395 | "# arrange_widgets_in_grid(controls)" 396 | ] 397 | }, 398 | { 399 | "cell_type": "code", 400 | "execution_count": null, 401 | "metadata": { 402 | "collapsed": true 403 | }, 404 | "outputs": [], 405 | "source": [] 406 | } 407 | ], 408 | "metadata": { 409 | "anaconda-cloud": {}, 410 | "kernelspec": { 411 | "display_name": "Python [Root]", 412 | "language": "python", 413 | "name": "Python [Root]" 414 | }, 415 | "language_info": { 416 | "codemirror_mode": { 417 | "name": "ipython", 418 | "version": 3 419 | }, 420 | "file_extension": ".py", 421 | "mimetype": "text/x-python", 422 | "name": "python", 423 | "nbconvert_exporter": "python", 424 | "pygments_lexer": "ipython3", 425 | "version": "3.5.2" 426 | }, 427 | "widgets": { 428 | "state": { 429 | "1d20a67d44bf4323af0e052bcdfdfcff": { 430 | "views": [ 431 | { 432 | "cell_index": 10 433 | } 434 | ] 435 | } 436 | }, 437 | "version": "1.2.0" 438 | } 439 | }, 440 | "nbformat": 4, 441 | "nbformat_minor": 1 442 | } 443 | --------------------------------------------------------------------------------