├── .gitignore
├── README.md
├── challenge
├── evaluate.py
└── sample_student.py
├── graphics
├── anisotropic_examples-01.png
├── anisotrpic_examples.ai
├── averaging_slides
│ ├── 01.png
│ └── 02.png
├── brick_ball_cylinder_2.gif
├── depth_of_field.jpg
├── dividing_line_medium.png
├── easy_examples.png
├── filter_animation_one
│ ├── Adobe Premiere Pro Auto-Save
│ │ └── filter_animation_one.prproj
│ ├── filter_animation_one.ai
│ ├── filter_animation_one.prproj
│ ├── filter_animation_one_1-01.gif
│ ├── filter_animation_one_1-01.png
│ ├── filter_animation_one_2-01.png
│ ├── filter_animation_one_3-01.png
│ ├── filter_animation_one_4-01.png
│ ├── filter_animation_one_5-01.png
│ ├── filter_animation_one_6-01.png
│ ├── filter_animation_one_7-01.png
│ ├── filter_animation_one_8-01.png
│ └── filter_animation_one_9-01.png
├── filtering_breakdown_one-01.png
├── filtering_breakdown_one.ai
├── filtering_breakdown_three-01.png
├── filtering_breakdown_three.ai
├── full_size_brick.jpg
├── hart_and_duda-01.png
├── hart_space
│ ├── hart_space_0-01.png
│ ├── hart_space_1-01.png
│ ├── hart_space_2-01.png
│ ├── hart_space_3-01.png
│ └── hart_space_4-01.png
├── hough_accumulator
│ ├── hough_accumulator_1.png
│ ├── hough_accumulator_2.png
│ └── hough_accumulator_3.png
├── hough_idea_kernel
│ ├── 01.png
│ ├── 02.png
│ ├── 03.png
│ ├── 04.png
│ └── 05.png
├── hough_intersection_proof-01.png
├── hough_problem_statement-01.png
├── hough_proof_followup-01.png
├── hough_question_eight-01.png
├── hough_question_five-01.png
├── hough_question_four-01.png
├── hough_question_one-01.png
├── hough_question_six.png
├── hough_question_three-01.png
├── houghs_problem-01.png
├── houghs_solution-01.png
├── integral_geometry_line_a.png
├── line_finding_motivation-01.png
├── line_finding_motivation.ai
├── local_averaging.ai
├── local_averaging_dot_product.ai
├── magnitude_and_direction-01.png
├── original_mit_crew-01.png
├── question_one-01.png
├── question_one.ai
├── question_seven-01.png
├── question_six-01.png
├── question_six.ai
├── question_three-01.png
├── question_two-01.png
├── question_two.ai
├── roberts_cross-01.png
├── roberts_cross_maximizers-01.png
├── roberts_cross_maximizers.ai
├── roberts_cross_vs_sobel-01.png
├── roberts_equations.png
├── roberts_thesis-01.png
├── rosenfeld_hough-01.png
├── sobel_and_feldman-01.png
├── sobel_and_feldman.ai
├── sobel_audience-01.png
├── sobel_audience.ai
├── sobel_operator_summary-01.png
├── sobel_question_four-01.png
├── sobel_question_one-01.png
├── sobel_question_three-01.png
├── sobel_question_two-01.png
├── sobel_vector_field-01.png
├── spacer_small.png
├── starbucks_giftcard.jpg
├── summer_project_abstract-01.png
├── summer_project_goals-01.png
└── the_bubble_chamber-01.png
├── notebooks
├── Image Filtering.ipynb
├── Robert's Cross.ipynb
├── The Hough Transform [Part 1].ipynb
├── The Hough Transform [Part 2].ipynb
├── The Original Problem Challenge Description.ipynb
└── The Sobel–Feldman Operator.ipynb
├── papers
├── history_and_def_of_sobel_operator.pdf
├── roberts_thesis.pdf
└── summer_vision_project.pdf
├── requirements.txt
└── util
├── filters.py
├── get_and_unpack.py
├── hough_accumulator.py
└── image.py
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Packages #
3 | ############
4 | # it's better to unpack these files and commit the raw source
5 | # git has its own built in compression methods
6 | *.7z
7 | *.dmg
8 | *.gz
9 | *.iso
10 | *.jar
11 | *.rar
12 | *.tar
13 | *.zip
14 | *.tmp
15 |
16 | # Notebook Checkpoints #
17 | #######################
18 | *.ipynb_checkpoints
19 |
20 | # Complied python modules #
21 | ##########################
22 | *.pyc
23 | __pycache__
24 |
25 | # Larger Files downloaded from elsewhere #
26 | #########################################
27 | data/
28 | videos/
29 | deprecated/
30 |
31 | # Logs and databases #
32 | ######################
33 | *.log
34 | *.sql
35 | *.sqlite
36 |
37 | # OS generated files #
38 | ######################
39 | .DS_Store
40 | .DS_Store?
41 | ._*
42 | .Spotlight-V100
43 | .Trashes
44 | ehthumbs.db
45 | Thumbs.db
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # The Original Problem
2 |
3 | 
4 |
5 | **Computer Vision** has a very interesting history. It's roots really go all the way back to the beginning of computing and **Artifical Intelligence.** In these early days, it was unknown just how easy or difficult it would be to recreate the function of the human visual system. A great example of this is the 1966 MIT Summer Vision Project. Marvin Minsky and Seymour Papert, co-directors of the MIT AI Labratory, begun the summer with some ambitious goals:
6 |
7 | 
8 |
9 |
10 | Minsky and Papert assigned Gerald Sussman, an MIT undergraduate studunt as project lead, and setup specific goals for the group around recognizing specific objects in images, and seperating these objects from their backgrounds.
11 |
12 | 
13 |
14 | Just how hard is it to acheive the goals Minsky and Papert laid out? How has the field of computer vision advance since that summer? Are these tasks trivial now, 50+ years later? Do we understand how the human visual system works? Just how hard *is* computer vision and how far have we come?
15 |
16 |
17 | ## This Repository
18 |
19 | This repository is all about spending some time the with **the original problem** posed by Minsky and Papert. Working through this problem is a great way to begin learning **computer vision.**
20 |
21 | 
22 |
23 |
24 | The repository is broadly divided into two areas: **notebooks** and a **programming challenge**. The programming challenge is described in more detail below, and closely follows the goals setup by Minsky and Papert back in 1966. The notebooks are here to give you some help along the way.
25 |
26 |
27 | ## Notebooks
28 |
29 | | Section | Notebook | Required Reading/Viewing | Additional Reading/Viewing | Code Developed |
30 | | ------- | ------------- | --------------------------- | -------------------------- | -------------- |
31 | | 1 | [The Original Problem](http://www.welchlabs.io/unccv/the_original_problem/notebooks/top.html) | [The Summer Vision Project](papers/summer_vision_project.pdf) | - | - |
32 | | 2 | [Robert's Cross](http://www.welchlabs.io/unccv/the_original_problem/notebooks/roberts_cross.html) | [Only Abstact and Pages 25-27 - Machine perception of 3d solids](papers/roberts_thesis.pdf)| - | convert_to_grayscale, roberts_cross |
33 | | 3 | [Image Filtering](http://www.welchlabs.io/unccv/the_original_problem/notebooks/image_filtering.html) | [How Blurs & Filters Work - Computerphile](https://youtu.be/C_zFhWdM4ic) | - | make_gaussian_kernel, filter_2d |
34 | | 4 | [The Sobel–Feldman Operator](http://www.welchlabs.io/unccv/the_original_problem/notebooks/sobel.html) | [Finding the Edges (Sobel Operator) - Computerphile](https://youtu.be/uihBwtPIBxM) | [History of Sobel](papers/history_and_def_of_sobel_operator.pdf) | - |
35 | | 5 | [The Hough Transform [Part 1]](http://www.welchlabs.io/unccv/the_original_problem/notebooks/hough_1.html) | | [Pattern classification Section 9.2.3](http://a.co/4o6oefR), [Bubble Chamber Video](https://www.youtube.com/watch?v=basLNz6frO8)| - |
36 | | 6 | [The Hough Transform [Part 2]](http://www.welchlabs.io/unccv/the_original_problem/notebooks/hough_2.html) | [How the Hough Transform was Invented](http://www.rci.rutgers.edu/~shunsun/resource/Hough_Transform.pdf) | [Use of the Hough transformation to detect lines and curves in pictures.](https://www.cse.unr.edu/~bebis/CS474/Handouts/HoughTransformPaper.pdf) | HoughAccumulator|
37 |
38 | ### Viewing Notebooks
39 | The links in the table above take you to externally hosted HTML exports of the notebooks. This works pretty well, except html won't render embedded slide shows unfortunately. The best way to view the notebooks is to clone this repo and run them yourself! Checkout the [setup instructions below](https://github.com/unccv/the_original_problem#setup).
40 |
41 | ### Animations
42 | The notebooks in this repository make frequent use of gif animations. These files are pretty large, so we don't store them on github, and they unfortunately won't show up when viewing the notebooks via github. The ideal way to view the notebooks is to clone the repo, download the videos, and use the recommended jupyterthemes below. Instructions on downloading videos are [below](http://github.com/unccv/the_original_problem#downloading-videos).
43 |
44 | ### Note on Launching the Jupyter Notebooks
45 | To properly view the images and animations, please launch your jupyter notebook from the root directory of this repository.
46 |
47 |
48 | ## Programming Challenge
49 |
50 | ### Instructions
51 |
52 | - Write a method `classify.py` that takes in an image and returns a prediction - ball, brick, or cylinder.
53 | - An example script in located in challenge/sample_student.py
54 | - Your script will be automatically evaluated on a set of test images.
55 | - The testing images are quite similar to the training images, and organized into the same difficulty categories.
56 | - You are allowed 10 submissions to the evaluation server, which will provide immediate feedback.
57 |
58 | ### The Data
59 |
60 | #### Easy Examples
61 | 
62 |
63 | ### Grading
64 | Following the progression set out the MIT the summer project, we'll start with easy images, and move to more difficult image with more complex backgrounds as we progress. For each difficulty level, we will compute the average accuracy of your classifier. We will then compute an average overall accuracy, weighting easier examples more:
65 |
66 | ````
67 | overall_accuracy = 0.5*accuracy_easy
68 | + 0.2*accuracy_medium_1
69 | + 0.2*accuracy_medium_2
70 | + 0.1*accuracy_hard
71 | ````
72 |
73 | | Overall Accuracy | Points |
74 | | ------------- |:-------------:|
75 | | >= 0.6 | 10/10 |
76 | | 0.55 <= a < 0.6 | 9/10|
77 | | 0.5 <= a < 0.55 | 8/10 |
78 | | 0.45 <= a < 0.5 | 7/10 |
79 | | 0.40 <= a < 0.45 | 6/10 |
80 | | 0.35 <= a < 0.40 | 5/10 |
81 | | a < 0.35 | 4/10 |
82 | | Non-running code | 0/10|
83 |
84 | #### A quick note on difficulty
85 | Depending on your background, this challenge may feel a bit like getting thrown into the deep end. If it feels a bit daunting - that's ok! Half of the purpose of this assignement is to help you develop an appreciation for **why** computer vision is so hard. As you may have already guessed, Misky, Sussman, and Papert did **not** reach their summer goals - and I'm not expecting you to either. The grading table above reflects this - for example, if you're able to get 90% accuracy on the easy examples, and simply guess randomly on the rest of the examples, you'll earn 10/10 points.
86 |
87 | ## Setup
88 |
89 | The Python 3 [Anaconda Distribution](https://www.anaconda.com/download) is the easiest way to get going with the notebooks and code presented here.
90 |
91 | (Optional) You may want to create a virtual environment for this repository:
92 |
93 | ~~~
94 | conda create -n cv python=3
95 | source activate cv
96 | ~~~
97 |
98 | You'll need to install the jupyter notebook to run the notebooks:
99 |
100 | ~~~
101 | conda install jupyter
102 |
103 | # You may also want to install nb_conda (Enables some nice things like change virtual environments within the notebook)
104 | conda install nb_conda
105 | ~~~
106 |
107 | This repository requires the installation of a few extra packages, you can install them all at once with:
108 | ~~~
109 | pip install -r requirements.txt
110 | ~~~
111 |
112 | (Optional) [jupyterthemes](https://github.com/dunovank/jupyter-themes) can be nice when presenting notebooks, as it offers some cleaner visual themes than the stock notebook, and makes it easy to adjust the default font size for code, markdown, etc. You can install with pip:
113 |
114 | ~~~
115 | pip install jupyterthemes
116 | ~~~
117 |
118 | Recommend jupyter them for **presenting** these notebook (type into terminal before launching notebook):
119 | ~~~
120 | jt -t grade3 -cellw=90% -fs=20 -tfs=20 -ofs=20 -dfs=20
121 | ~~~
122 |
123 | Recommend jupyter them for **viewing** these notebook (type into terminal before launching notebook):
124 | ~~~
125 | jt -t grade3 -cellw=90% -fs=14 -tfs=14 -ofs=14 -dfs=14
126 | ~~~
127 |
128 | ### Downloading Data
129 | For larger files such as data and videos, I've provided download scripts to download these files from welchlabs.io. These files can be pretty big, so you may want to grab a cup of your favorite beverage to enjoy while downloading. The script can be run from within the jupyter notebooks or from the terminal:
130 |
131 | ~~~
132 | python util/get_and_unpack.py -url http://www.welchlabs.io/unccv/the_original_problem/data/data.zip
133 | ~~~
134 |
135 | Alternatively, you can download [download data manually](http://www.welchlabs.io/unccv/the_original_problem/data/data.zip), unzip and place in this directory.
136 |
137 |
138 | ### Downloading Videos
139 |
140 | Run the script below or call it from the notebooks:
141 |
142 | ~~~
143 | python util/get_and_unpack.py -url http://www.welchlabs.io/unccv/the_original_problem/videos.zip
144 | ~~~
145 |
146 | Alternatively, you can download [download videos manually](http://www.welchlabs.io/unccv/the_original_problem/videos.zip), unzip and place in this directory.
147 |
148 |
149 |
150 |
--------------------------------------------------------------------------------
/challenge/evaluate.py:
--------------------------------------------------------------------------------
1 | ## ------------------------- ##
2 | ##
3 | ## evaluate.py
4 | ## Basic image processing utilties.
5 | ##
6 | ##
7 | ## ------------------------- ##
8 |
9 | import numpy as np
10 | import glob
11 | from easydict import EasyDict
12 | from matplotlib.pyplot import imread
13 | import time
14 |
15 | #Import student's method:
16 | from sample_student import classify
17 |
18 | program_start = time.time()
19 |
20 | dataset_names = ['easy', 'medium_1', 'medium_2', 'hard']
21 | weights = [0.5, 0.2, 0.2, 0.1]
22 | classes = ['ball', 'brick', 'cylinder']
23 | data_path = '../data' #Assuming data is one directory up.
24 |
25 | dataset_weights = {}
26 | for i in range(len(dataset_names)):
27 | dataset_weights[dataset_names[i]] = weights[i]
28 |
29 | #Store data performance data in a nested easydict:
30 | performance = EasyDict()
31 | total_time = 0
32 |
33 | #Iterate through images:
34 | for dataset_name in dataset_names:
35 | performance[dataset_name] = EasyDict()
36 | performance[dataset_name]['overall'] = np.array([0, 0]) #overall Correct/incorrect
37 |
38 | for image_class in classes:
39 | performance[dataset_name][image_class] = np.array([0, 0])
40 | image_paths = glob.glob(data_path + '/'
41 | + dataset_name + '/'
42 | + image_class + '/*.jpg')
43 |
44 | for image_path in image_paths:
45 | im = imread(image_path)
46 |
47 | start_time = time.time()
48 | prediction = classify(im)
49 | end_time = time.time()
50 | total_time += (end_time - start_time)
51 |
52 | if image_class == prediction:
53 | performance[dataset_name][image_class][0] += 1
54 | else:
55 | performance[dataset_name][image_class][1] += 1
56 |
57 | #Tally overall performance for class
58 | performance[dataset_name]['overall'] = performance[dataset_name]['overall'] \
59 | + performance[dataset_name][image_class]
60 |
61 |
62 | #Print out errors:
63 | print('Fraction of Correct Predictions: ')
64 | overall_accuracy = 0
65 | for dataset_name in dataset_names:
66 | total_correct, total_incorrect = performance[dataset_name]['overall']
67 | total = total_correct + total_incorrect
68 | accuracy = np.round(float(total_correct)/total, 4)
69 | overall_accuracy += accuracy * dataset_weights[dataset_name]
70 | performance[dataset_name]['accuracy'] = accuracy
71 | print(dataset_name + ': ' + \
72 | '(' + str(total_correct) + '/' + str(total) + ' = ' + \
73 | str(accuracy) + ')')
74 |
75 | for image_class in classes:
76 | print(' ' + image_class + ': '
77 | + str(performance[dataset_name][image_class][0])
78 | + '/'
79 | + str(np.sum(performance[dataset_name][image_class])))
80 |
81 | overall_accuracy = np.round(overall_accuracy, 2)
82 | score = 0
83 |
84 | if overall_accuracy >= 0.6:
85 | score = 10
86 | elif overall_accuracy >= 0.55:
87 | score = 9
88 | elif overall_accuracy >= 0.5:
89 | score = 8
90 | elif overall_accuracy >= 0.45:
91 | score = 7
92 | elif overall_accuracy >= 0.4:
93 | score = 6
94 | elif overall_accuracy >= 0.35:
95 | score = 5
96 | elif overall_accuracy >= 0:
97 | score = 4
98 |
99 |
100 | print("\nOverall Accuracy = ", overall_accuracy)
101 | print("Score = ", score)
102 |
103 | program_end = time.time()
104 | complete_time = program_end - program_start
105 | total_time = round(total_time, 5)
106 | complete_time = round(complete_time, 5)
107 |
108 | print("Classification time (seconds): = ", total_time)
109 | print("Program completetion time (seconds): = ", complete_time)
110 |
--------------------------------------------------------------------------------
/challenge/sample_student.py:
--------------------------------------------------------------------------------
1 | ## ---------------------------- ##
2 | ##
3 | ## sample_student.py
4 | ##
5 | ## Example student submission for programming challenge. A few things:
6 | ## 1. Before submitting, change the name of this file to your firstname_lastname.py.
7 | ## 2. Be sure not to change the name of the method below, classify.py
8 | ## 3. In this challenge, you are only permitted to import numpy and methods from
9 | ## the util module in this repository. Note that if you make any changes to your local
10 | ## util module, these won't be reflected in the util module that is imported by the
11 | ## auto grading algorithm.
12 | ## 4. Anti-plagarism checks will be run on your submission
13 | ##
14 | ##
15 | ## ---------------------------- ##
16 |
17 |
18 | import numpy as np
19 | #It's kk to import whatever you want from the local util module if you would like:
20 | #from util.X import ...
21 |
22 | def classify(im):
23 | '''
24 | Example submission for coding challenge.
25 |
26 | Args: im (nxmx3) unsigned 8-bit color image
27 | Returns: One of three strings: 'brick', 'ball', or 'cylinder'
28 |
29 | '''
30 |
31 |
32 |
33 | #Let's guess randomly! Maybe we'll get lucky.
34 | labels = ['brick', 'ball', 'cylinder']
35 | random_integer = np.random.randint(low = 0, high = 3)
36 |
37 | return labels[random_integer]
--------------------------------------------------------------------------------
/graphics/anisotropic_examples-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/anisotropic_examples-01.png
--------------------------------------------------------------------------------
/graphics/anisotrpic_examples.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/anisotrpic_examples.ai
--------------------------------------------------------------------------------
/graphics/averaging_slides/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/averaging_slides/01.png
--------------------------------------------------------------------------------
/graphics/averaging_slides/02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/averaging_slides/02.png
--------------------------------------------------------------------------------
/graphics/brick_ball_cylinder_2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/brick_ball_cylinder_2.gif
--------------------------------------------------------------------------------
/graphics/depth_of_field.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/depth_of_field.jpg
--------------------------------------------------------------------------------
/graphics/dividing_line_medium.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/dividing_line_medium.png
--------------------------------------------------------------------------------
/graphics/easy_examples.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/easy_examples.png
--------------------------------------------------------------------------------
/graphics/filter_animation_one/Adobe Premiere Pro Auto-Save/filter_animation_one.prproj:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/filter_animation_one/Adobe Premiere Pro Auto-Save/filter_animation_one.prproj
--------------------------------------------------------------------------------
/graphics/filter_animation_one/filter_animation_one.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/filter_animation_one/filter_animation_one.ai
--------------------------------------------------------------------------------
/graphics/filter_animation_one/filter_animation_one.prproj:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/filter_animation_one/filter_animation_one.prproj
--------------------------------------------------------------------------------
/graphics/filter_animation_one/filter_animation_one_1-01.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/filter_animation_one/filter_animation_one_1-01.gif
--------------------------------------------------------------------------------
/graphics/filter_animation_one/filter_animation_one_1-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/filter_animation_one/filter_animation_one_1-01.png
--------------------------------------------------------------------------------
/graphics/filter_animation_one/filter_animation_one_2-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/filter_animation_one/filter_animation_one_2-01.png
--------------------------------------------------------------------------------
/graphics/filter_animation_one/filter_animation_one_3-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/filter_animation_one/filter_animation_one_3-01.png
--------------------------------------------------------------------------------
/graphics/filter_animation_one/filter_animation_one_4-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/filter_animation_one/filter_animation_one_4-01.png
--------------------------------------------------------------------------------
/graphics/filter_animation_one/filter_animation_one_5-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/filter_animation_one/filter_animation_one_5-01.png
--------------------------------------------------------------------------------
/graphics/filter_animation_one/filter_animation_one_6-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/filter_animation_one/filter_animation_one_6-01.png
--------------------------------------------------------------------------------
/graphics/filter_animation_one/filter_animation_one_7-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/filter_animation_one/filter_animation_one_7-01.png
--------------------------------------------------------------------------------
/graphics/filter_animation_one/filter_animation_one_8-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/filter_animation_one/filter_animation_one_8-01.png
--------------------------------------------------------------------------------
/graphics/filter_animation_one/filter_animation_one_9-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/filter_animation_one/filter_animation_one_9-01.png
--------------------------------------------------------------------------------
/graphics/filtering_breakdown_one-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/filtering_breakdown_one-01.png
--------------------------------------------------------------------------------
/graphics/filtering_breakdown_one.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/filtering_breakdown_one.ai
--------------------------------------------------------------------------------
/graphics/filtering_breakdown_three-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/filtering_breakdown_three-01.png
--------------------------------------------------------------------------------
/graphics/filtering_breakdown_three.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/filtering_breakdown_three.ai
--------------------------------------------------------------------------------
/graphics/full_size_brick.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/full_size_brick.jpg
--------------------------------------------------------------------------------
/graphics/hart_and_duda-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hart_and_duda-01.png
--------------------------------------------------------------------------------
/graphics/hart_space/hart_space_0-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hart_space/hart_space_0-01.png
--------------------------------------------------------------------------------
/graphics/hart_space/hart_space_1-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hart_space/hart_space_1-01.png
--------------------------------------------------------------------------------
/graphics/hart_space/hart_space_2-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hart_space/hart_space_2-01.png
--------------------------------------------------------------------------------
/graphics/hart_space/hart_space_3-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hart_space/hart_space_3-01.png
--------------------------------------------------------------------------------
/graphics/hart_space/hart_space_4-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hart_space/hart_space_4-01.png
--------------------------------------------------------------------------------
/graphics/hough_accumulator/hough_accumulator_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hough_accumulator/hough_accumulator_1.png
--------------------------------------------------------------------------------
/graphics/hough_accumulator/hough_accumulator_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hough_accumulator/hough_accumulator_2.png
--------------------------------------------------------------------------------
/graphics/hough_accumulator/hough_accumulator_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hough_accumulator/hough_accumulator_3.png
--------------------------------------------------------------------------------
/graphics/hough_idea_kernel/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hough_idea_kernel/01.png
--------------------------------------------------------------------------------
/graphics/hough_idea_kernel/02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hough_idea_kernel/02.png
--------------------------------------------------------------------------------
/graphics/hough_idea_kernel/03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hough_idea_kernel/03.png
--------------------------------------------------------------------------------
/graphics/hough_idea_kernel/04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hough_idea_kernel/04.png
--------------------------------------------------------------------------------
/graphics/hough_idea_kernel/05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hough_idea_kernel/05.png
--------------------------------------------------------------------------------
/graphics/hough_intersection_proof-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hough_intersection_proof-01.png
--------------------------------------------------------------------------------
/graphics/hough_problem_statement-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hough_problem_statement-01.png
--------------------------------------------------------------------------------
/graphics/hough_proof_followup-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hough_proof_followup-01.png
--------------------------------------------------------------------------------
/graphics/hough_question_eight-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hough_question_eight-01.png
--------------------------------------------------------------------------------
/graphics/hough_question_five-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hough_question_five-01.png
--------------------------------------------------------------------------------
/graphics/hough_question_four-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hough_question_four-01.png
--------------------------------------------------------------------------------
/graphics/hough_question_one-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hough_question_one-01.png
--------------------------------------------------------------------------------
/graphics/hough_question_six.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hough_question_six.png
--------------------------------------------------------------------------------
/graphics/hough_question_three-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/hough_question_three-01.png
--------------------------------------------------------------------------------
/graphics/houghs_problem-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/houghs_problem-01.png
--------------------------------------------------------------------------------
/graphics/houghs_solution-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/houghs_solution-01.png
--------------------------------------------------------------------------------
/graphics/integral_geometry_line_a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/integral_geometry_line_a.png
--------------------------------------------------------------------------------
/graphics/line_finding_motivation-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/line_finding_motivation-01.png
--------------------------------------------------------------------------------
/graphics/line_finding_motivation.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/line_finding_motivation.ai
--------------------------------------------------------------------------------
/graphics/local_averaging.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/local_averaging.ai
--------------------------------------------------------------------------------
/graphics/local_averaging_dot_product.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/local_averaging_dot_product.ai
--------------------------------------------------------------------------------
/graphics/magnitude_and_direction-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/magnitude_and_direction-01.png
--------------------------------------------------------------------------------
/graphics/original_mit_crew-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/original_mit_crew-01.png
--------------------------------------------------------------------------------
/graphics/question_one-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/question_one-01.png
--------------------------------------------------------------------------------
/graphics/question_one.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/question_one.ai
--------------------------------------------------------------------------------
/graphics/question_seven-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/question_seven-01.png
--------------------------------------------------------------------------------
/graphics/question_six-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/question_six-01.png
--------------------------------------------------------------------------------
/graphics/question_six.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/question_six.ai
--------------------------------------------------------------------------------
/graphics/question_three-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/question_three-01.png
--------------------------------------------------------------------------------
/graphics/question_two-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/question_two-01.png
--------------------------------------------------------------------------------
/graphics/question_two.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/question_two.ai
--------------------------------------------------------------------------------
/graphics/roberts_cross-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/roberts_cross-01.png
--------------------------------------------------------------------------------
/graphics/roberts_cross_maximizers-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/roberts_cross_maximizers-01.png
--------------------------------------------------------------------------------
/graphics/roberts_cross_maximizers.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/roberts_cross_maximizers.ai
--------------------------------------------------------------------------------
/graphics/roberts_cross_vs_sobel-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/roberts_cross_vs_sobel-01.png
--------------------------------------------------------------------------------
/graphics/roberts_equations.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/roberts_equations.png
--------------------------------------------------------------------------------
/graphics/roberts_thesis-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/roberts_thesis-01.png
--------------------------------------------------------------------------------
/graphics/rosenfeld_hough-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/rosenfeld_hough-01.png
--------------------------------------------------------------------------------
/graphics/sobel_and_feldman-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/sobel_and_feldman-01.png
--------------------------------------------------------------------------------
/graphics/sobel_and_feldman.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/sobel_and_feldman.ai
--------------------------------------------------------------------------------
/graphics/sobel_audience-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/sobel_audience-01.png
--------------------------------------------------------------------------------
/graphics/sobel_audience.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/sobel_audience.ai
--------------------------------------------------------------------------------
/graphics/sobel_operator_summary-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/sobel_operator_summary-01.png
--------------------------------------------------------------------------------
/graphics/sobel_question_four-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/sobel_question_four-01.png
--------------------------------------------------------------------------------
/graphics/sobel_question_one-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/sobel_question_one-01.png
--------------------------------------------------------------------------------
/graphics/sobel_question_three-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/sobel_question_three-01.png
--------------------------------------------------------------------------------
/graphics/sobel_question_two-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/sobel_question_two-01.png
--------------------------------------------------------------------------------
/graphics/sobel_vector_field-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/sobel_vector_field-01.png
--------------------------------------------------------------------------------
/graphics/spacer_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/spacer_small.png
--------------------------------------------------------------------------------
/graphics/starbucks_giftcard.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/starbucks_giftcard.jpg
--------------------------------------------------------------------------------
/graphics/summer_project_abstract-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/summer_project_abstract-01.png
--------------------------------------------------------------------------------
/graphics/summer_project_goals-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/summer_project_goals-01.png
--------------------------------------------------------------------------------
/graphics/the_bubble_chamber-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/graphics/the_bubble_chamber-01.png
--------------------------------------------------------------------------------
/notebooks/The Hough Transform [Part 1].ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# **The Hough Transform [Part 1]**"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "**Optional Reading**\n",
15 | "1. Duda, Richard O., Peter E. Hart, and David G. Stork. Pattern classification. Vol. 2. New York: Wiley, 1973. **Section 9.2.3**\n",
16 | "\n",
17 | "**Recommended [Jupyter Theme](https://github.com/dunovank/jupyter-themes) for presenting this notebook:**\n",
18 | "````\n",
19 | "jt -t grade3 -cellw=90% -fs=20 -tfs=20 -ofs=20\n",
20 | "````"
21 | ]
22 | },
23 | {
24 | "cell_type": "code",
25 | "execution_count": 4,
26 | "metadata": {},
27 | "outputs": [
28 | {
29 | "data": {
30 | "text/html": [
31 | ""
32 | ],
33 | "text/plain": [
34 | ""
35 | ]
36 | },
37 | "metadata": {},
38 | "output_type": "display_data"
39 | }
40 | ],
41 | "source": [
42 | "from IPython.core.display import display, HTML\n",
43 | "display(HTML(\"\"))"
44 | ]
45 | },
46 | {
47 | "cell_type": "markdown",
48 | "metadata": {},
49 | "source": [
50 | ""
51 | ]
52 | },
53 | {
54 | "cell_type": "markdown",
55 | "metadata": {},
56 | "source": [
57 | "- Today we're going to talk about how we can find lines, or other shapes, using \"edge images\", like the ones we computed in our lecture on the Sobel-Feldman operator.\n",
58 | "- One of the first people to think seriously about this problem was **Paul Hough**, while working on an interesting experimental physics problem. "
59 | ]
60 | },
61 | {
62 | "cell_type": "markdown",
63 | "metadata": {},
64 | "source": [
65 | "---"
66 | ]
67 | },
68 | {
69 | "cell_type": "markdown",
70 | "metadata": {},
71 | "source": [
72 | ""
73 | ]
74 | },
75 | {
76 | "cell_type": "markdown",
77 | "metadata": {},
78 | "source": [
79 | "- In 1952 [Donald A. Glaser](https://en.wikipedia.org/wiki/Donald_A._Glaser) invented a new tool for studying partical physics - the **[bubble chamber](https://en.wikipedia.org/wiki/Bubble_chamber)**. \n",
80 | " - Glaser was awarded the Nobel Prize in 1960 for his invention.\n",
81 | "- The bubble chamber worked by tracing the bubbles formed by charged particles moving through a superheated liquid. \n",
82 | "- Physicists took pictures of the bubbles as particles moved through the chamber using multiple cameras mounted around the bubble chamber.\n",
83 | "- By analyzing the the radius of curvature of the bubbles, physicist could infer the momentum of individual particles.\n",
84 | "- Bubble chambers and the data they produce have allowed physicist to make some pretty incredible discoveries, such as **weak neutral currents** - [Nice video from 60 symbols](https://www.youtube.com/watch?v=basLNz6frO8)"
85 | ]
86 | },
87 | {
88 | "cell_type": "markdown",
89 | "metadata": {},
90 | "source": [
91 | "---"
92 | ]
93 | },
94 | {
95 | "cell_type": "markdown",
96 | "metadata": {},
97 | "source": [
98 | "# **A Minor Problem with the Bubble Chamber**"
99 | ]
100 | },
101 | {
102 | "cell_type": "markdown",
103 | "metadata": {},
104 | "source": [
105 | ""
106 | ]
107 | },
108 | {
109 | "cell_type": "markdown",
110 | "metadata": {
111 | "collapsed": true
112 | },
113 | "source": [
114 | "- One issue with the bubble chamber was handling sheer volume of data it produced. \n",
115 | "- In the early 1950s, **Paul Hough**, a recent Cornell PhD graduate joined Donald Glaser, the inventor of the Bubble Chamber, at the University of Michigan. \n",
116 | "- During this period, Hough began working on methods to automate the tedious task of detecting particle tracks in bubble chambers. [Fun Talk from Paul Hough on the bubble chamber](https://www.osti.gov/servlets/purl/4805882).\n",
117 | "- One particularly difficult problem was automatically detecting lines in images.\n",
118 | "- Let's give this problem a little thought:"
119 | ]
120 | },
121 | {
122 | "cell_type": "markdown",
123 | "metadata": {},
124 | "source": [
125 | ""
126 | ]
127 | },
128 | {
129 | "cell_type": "markdown",
130 | "metadata": {},
131 | "source": [
132 | "- Let's think about our pixels or edges as points on the $xy$ plane for a moment, and consider how we might fit one or more lines to a set of such points.\n",
133 | "- As we saw in our lecture on The Sobel Feldman Edge detector, we have some good algorithms that can return high values for edges - now we need to think about how we can group those detections into a single line.\n",
134 | "- [Mild Disclaimer] We're leaving out one step taken by Hough. Before fitting lines, Hough broke images into small \"framelets\", and analyzed each framelet seperately. This meant that Hough typically only needed to find one line within each framlet. He're we're considering the slightly more complex case of how we might find multiple lines, but the outcome will be the same. \n",
135 | "- **What do you think?**\n",
136 | "- **What would you do if you woke up in Hough's shoes?**\n",
137 | "- **Can you think of an algorithm that would give us the best fit set of lines to a set of points, while ignoring outliers?**"
138 | ]
139 | },
140 | {
141 | "cell_type": "markdown",
142 | "metadata": {},
143 | "source": [
144 | "___"
145 | ]
146 | },
147 | {
148 | "cell_type": "markdown",
149 | "metadata": {},
150 | "source": [
151 | ""
152 | ]
153 | },
154 | {
155 | "cell_type": "markdown",
156 | "metadata": {},
157 | "source": [
158 | ""
159 | ]
160 | },
161 | {
162 | "cell_type": "markdown",
163 | "metadata": {},
164 | "source": [
165 | "- One relatively simple approach here is to **\"try all the lines\".** \n",
166 | "- For each unique line formed by 2 of our points, we could check to see if any on other points lie on this line.\n",
167 | "- We could then return all the line or lines that intersect a relateively large number of points.\n",
168 | " - There are lots of other valid approaches here, such as RANSAC - check out Forsyth, David A., and Jean Ponce. Computer vision: a modern approach. Prentice Hall Professional Technical Reference, 2002. **Chapter 10.**\n",
169 | "- Let's give the the **\"try all the lines\"** approach a little more thought."
170 | ]
171 | },
172 | {
173 | "cell_type": "markdown",
174 | "metadata": {},
175 | "source": [
176 | ""
177 | ]
178 | },
179 | {
180 | "cell_type": "markdown",
181 | "metadata": {},
182 | "source": [
183 | ""
184 | ]
185 | },
186 | {
187 | "cell_type": "markdown",
188 | "metadata": {},
189 | "source": [
190 | "---"
191 | ]
192 | },
193 | {
194 | "cell_type": "markdown",
195 | "metadata": {},
196 | "source": [
197 | ""
198 | ]
199 | },
200 | {
201 | "cell_type": "markdown",
202 | "metadata": {
203 | "collapsed": true
204 | },
205 | "source": [
206 | "---"
207 | ]
208 | },
209 | {
210 | "cell_type": "markdown",
211 | "metadata": {
212 | "collapsed": true
213 | },
214 | "source": [
215 | ""
216 | ]
217 | },
218 | {
219 | "cell_type": "markdown",
220 | "metadata": {},
221 | "source": [
222 | "*Explanation*\n",
223 | "- Each of our $n$ points could be paired with any of the other $n-1$ points, making for $n \\cdot (n-1)$ possible combinations of two points. \n",
224 | "- However, half of these pairs are redundant, because a line from $(x_1, y_1)$ to $(x_2, y_2)$ in indistinguishable from a line from $(x_2, y_2)$ to $(x_1, y_1)$. So we need to divide our number of possible pairs, resulting in: \n",
225 | "\n",
226 | "$$\n",
227 | "\\frac{n \\cdot (n-1)}{2} = \\frac{n^2}{2} - \\frac{n}{2} \\approx \\frac{n^2}{2}\n",
228 | "$$\n",
229 | "\n",
230 | "- So the correct answer is b.\n",
231 | "\n"
232 | ]
233 | },
234 | {
235 | "cell_type": "markdown",
236 | "metadata": {},
237 | "source": [
238 | "___"
239 | ]
240 | },
241 | {
242 | "cell_type": "markdown",
243 | "metadata": {},
244 | "source": [
245 | "# **Ok, so we're done?**"
246 | ]
247 | },
248 | {
249 | "cell_type": "markdown",
250 | "metadata": {},
251 | "source": [
252 | "- So we've found one way to find sets of of co-linear points, but **is this a good approach**?\n",
253 | "- Any possible problems we might run into applying to approach, to let's say, edges computed with the Sobel-Fieldman operator like the ones below?"
254 | ]
255 | },
256 | {
257 | "cell_type": "markdown",
258 | "metadata": {},
259 | "source": [
260 | ""
261 | ]
262 | },
263 | {
264 | "cell_type": "markdown",
265 | "metadata": {},
266 | "source": [
267 | "In practice, two big issues will likely pop up when we go to code our algorithm:\n",
268 | "\n",
269 | "**1. Slow AF.** As we figured out earlier, our \"try all the lines\" algorithm scales as $\\frac{n^2}{2}$. The images above are 256x256, and have, on average 250-500 edge pixels. This makes for between 30k and 125k lines we need to test. Further, these images are quite small by modern standards, and very low noise (<1% of pixels are edges). If we had a noisy [Full HD](https://en.wikipedia.org/wiki/1080p) image for example, where 10% of our pixels were detected as edges, this would make for $((1920 \\cdot 1080 \\cdot 0.1)^2)/2 \\approx 21B $ lines to test! This would be slow on a modern computer, and incomputable in the 1950s when Hough worked on this problem.\n",
270 | "\n",
271 | "**2. Susceptible to Noise.** The edge points that show up in our images above are not *exactly* co-linear. This means that testing each of our lines is a bit more complex. We could measure the distance of points to our line, as use some kind of thresholding label points as \"approximately co-linear\". This may work well, but the point here is that noise complicated our \"try all the lines\" approach. \n"
272 | ]
273 | },
274 | {
275 | "cell_type": "markdown",
276 | "metadata": {},
277 | "source": [
278 | "---"
279 | ]
280 | },
281 | {
282 | "cell_type": "markdown",
283 | "metadata": {},
284 | "source": [
285 | "## **Here's Where it Gets Interesting**\n",
286 | "\n"
287 | ]
288 | },
289 | {
290 | "cell_type": "markdown",
291 | "metadata": {},
292 | "source": [
293 | "- There is a very slick modern solution to Hough's problem that allows us to simultaneously address problems (1) and (2) above, called **The Hough Transform**. \n",
294 | "- What I think is really interesting here is that **Paul V. C. Hough did not create what we call the Hough Transform today.**\n",
295 | "- What he did figure out is the kernel of the idea. \n",
296 | "- After being puzzled with the tough problem of how to efficiently line detect noisy co-linear points in images, Hough had an interesting idea walking home one day from work."
297 | ]
298 | },
299 | {
300 | "cell_type": "code",
301 | "execution_count": 5,
302 | "metadata": {},
303 | "outputs": [],
304 | "source": [
305 | "#Little trick to progress through slides within the notebook\n",
306 | "from IPython.display import Image, display\n",
307 | "from ipywidgets import interact\n",
308 | "\n",
309 | "#Quick method to let me step through \"slides\"\n",
310 | "def slide_show(slide_num=1): \n",
311 | " display(Image('../graphics/hough_idea_kernel/' + str(slide_num).zfill(2) + '.png'))"
312 | ]
313 | },
314 | {
315 | "cell_type": "code",
316 | "execution_count": 6,
317 | "metadata": {
318 | "scrolled": false
319 | },
320 | "outputs": [
321 | {
322 | "data": {
323 | "application/vnd.jupyter.widget-view+json": {
324 | "model_id": "affd9bbca790422988c4b4aee79d7520",
325 | "version_major": 2,
326 | "version_minor": 0
327 | },
328 | "text/plain": [
329 | "interactive(children=(IntSlider(value=1, description='slide_num', max=5, min=1), Output()), _dom_classes=('wid…"
330 | ]
331 | },
332 | "metadata": {},
333 | "output_type": "display_data"
334 | }
335 | ],
336 | "source": [
337 | "interact(slide_show, slide_num = (1, 5));"
338 | ]
339 | },
340 | {
341 | "cell_type": "markdown",
342 | "metadata": {},
343 | "source": [
344 | "- Hough's idea involves transforming our points into a new space. \n",
345 | "- Specifically, the **parameter space** of 2D lines (sometimes called Hough Space).\n",
346 | "- The key idea is simple. Every point *becomes* a line. \n",
347 | " - The slope of the line is determined by the point's $y$ value.\n",
348 | " - The y-intercept of the line is determined by the point's $x$ value. \n",
349 | " - That's it. :)"
350 | ]
351 | },
352 | {
353 | "cell_type": "markdown",
354 | "metadata": {},
355 | "source": [
356 | "# **Now, why might this transformation be useful?**"
357 | ]
358 | },
359 | {
360 | "cell_type": "markdown",
361 | "metadata": {},
362 | "source": [
363 | ""
364 | ]
365 | },
366 | {
367 | "cell_type": "markdown",
368 | "metadata": {},
369 | "source": [
370 | "- What is the relationship between colinear points after being mapped to hough space?"
371 | ]
372 | },
373 | {
374 | "cell_type": "markdown",
375 | "metadata": {},
376 | "source": [
377 | ""
378 | ]
379 | },
380 | {
381 | "cell_type": "markdown",
382 | "metadata": {},
383 | "source": [
384 | "---\n"
385 | ]
386 | },
387 | {
388 | "cell_type": "markdown",
389 | "metadata": {},
390 | "source": [
391 | "- A careful look at our video suggest that colinear Points in the $xy$ plane become intersecting lines in hough space!\n",
392 | "- Let's see we we can prove our hunch!"
393 | ]
394 | },
395 | {
396 | "cell_type": "markdown",
397 | "metadata": {},
398 | "source": [
399 | ""
400 | ]
401 | },
402 | {
403 | "cell_type": "markdown",
404 | "metadata": {},
405 | "source": [
406 | "---"
407 | ]
408 | },
409 | {
410 | "cell_type": "markdown",
411 | "metadata": {},
412 | "source": [
413 | ""
414 | ]
415 | },
416 | {
417 | "cell_type": "markdown",
418 | "metadata": {},
419 | "source": [
420 | "- Ok, if you were able to prove this interesting fact, great!\n",
421 | "- If not, don't give up yet!\n",
422 | "- Before we go over the answer, let's try to figure out *where* our lines will intersect in Hough Space."
423 | ]
424 | },
425 | {
426 | "cell_type": "markdown",
427 | "metadata": {},
428 | "source": [
429 | ""
430 | ]
431 | },
432 | {
433 | "cell_type": "markdown",
434 | "metadata": {},
435 | "source": [
436 | "---"
437 | ]
438 | },
439 | {
440 | "cell_type": "markdown",
441 | "metadata": {},
442 | "source": [
443 | ""
444 | ]
445 | },
446 | {
447 | "cell_type": "markdown",
448 | "metadata": {},
449 | "source": [
450 | "---"
451 | ]
452 | },
453 | {
454 | "cell_type": "markdown",
455 | "metadata": {},
456 | "source": [
457 | ""
458 | ]
459 | },
460 | {
461 | "cell_type": "markdown",
462 | "metadata": {},
463 | "source": [
464 | "*Explanation*\n",
465 | "1. For colinear points $\\{ (x_i, y_i) \\}$, there must be some values of $m$ and $b$ such that $y_i = m x_i + b$, $\\forall i$. (There must be one line through the points)\n",
466 | "2. The equations of intersecting lines in Hough Space will be satisfied at mutual intersection points: $v_1 = y_i u_1 + x_i, \\forall i$. (When we plug in the intersection point $(u_1, v_1)$ into the equations of intersecting lines, each equation will hold true)\n",
467 | "3. With a little re-arrangement, we can show that (2) is mathematically equivalent to (1):"
468 | ]
469 | },
470 | {
471 | "cell_type": "markdown",
472 | "metadata": {},
473 | "source": [
474 | "$$\n",
475 | "v_1 = y_i u_1 + x_i \\\\\n",
476 | "y_i u_1 = v_1-x_i \\\\\n",
477 | "y_i = -\\frac{1}{u_1} x_i + \\frac{v_1}{u_1}\n",
478 | "$$"
479 | ]
480 | },
481 | {
482 | "cell_type": "markdown",
483 | "metadata": {},
484 | "source": [
485 | "This equation is equivalent to (1), given that $m = - \\frac{1}{u_i}$ and $b=\\frac{v_1}{u_1}$. QED."
486 | ]
487 | },
488 | {
489 | "cell_type": "markdown",
490 | "metadata": {},
491 | "source": [
492 | "Finally, we can use this result to solve our second problem, finding our intersection point. We just need to solve for $u_1$ and $v_1$: $u_i = -\\frac{1}{m}$, and $v_1 = b \\cdot u_1 = -\\frac{b}{m}$."
493 | ]
494 | },
495 | {
496 | "cell_type": "markdown",
497 | "metadata": {},
498 | "source": [
499 | "---"
500 | ]
501 | },
502 | {
503 | "cell_type": "markdown",
504 | "metadata": {},
505 | "source": [
506 | ""
507 | ]
508 | },
509 | {
510 | "cell_type": "markdown",
511 | "metadata": {},
512 | "source": [
513 | ""
514 | ]
515 | },
516 | {
517 | "cell_type": "markdown",
518 | "metadata": {},
519 | "source": [
520 | "# The problem of finding colinear points is **mathematically equivalent** to finding intersecting lines in Hough Space."
521 | ]
522 | },
523 | {
524 | "cell_type": "markdown",
525 | "metadata": {},
526 | "source": [
527 | ""
528 | ]
529 | },
530 | {
531 | "cell_type": "markdown",
532 | "metadata": {},
533 | "source": [
534 | "## Now What?"
535 | ]
536 | },
537 | {
538 | "cell_type": "markdown",
539 | "metadata": {},
540 | "source": [
541 | "---"
542 | ]
543 | },
544 | {
545 | "cell_type": "markdown",
546 | "metadata": {},
547 | "source": [
548 | "- Ok, so we've seen that we can pose our finding colinear points problem as finding intersecting lines in hough space. These problems are mathematically equivalent.\n",
549 | "- **But how does this really help us?** We started out with an approach to finding colinear points, \"trying all the lines\", that had a couple of issues:\n",
550 | " - **Slow**\n",
551 | " - **Susceptable to Noise**\n",
552 | "- Does solving our problem in hough space help us resolve either of this issues?!\n",
553 | "- This is where we need to come back to our larger story. We really need **two more ideas** to make this all work.\n",
554 | "- Next time, we'll finish our story and add the missing pieces that make the Hough Transform work.\n",
555 | "- Before we wrap up part 1 of this story though, let's look at one more issue with Hough's implementation of the transform that we'll also need to resolve. \n",
556 | "- Specifically, what happens when we draw horizontal lines:"
557 | ]
558 | },
559 | {
560 | "cell_type": "markdown",
561 | "metadata": {},
562 | "source": [
563 | ""
564 | ]
565 | },
566 | {
567 | "cell_type": "markdown",
568 | "metadata": {},
569 | "source": [
570 | "- As you can see horizontal lines result in a bit of a problem! They intersect at $\\infty$ in Hough Space!\n",
571 | " - We can see this in our equations above: $u_i = -\\frac{1}{m}$ $\\rightarrow$ $\\infty$ as $m \\rightarrow 0$.\n",
572 | "- Hough did have a solution to this - soving the problem twice - once with a $90^\\circ$ rotation!\n",
573 | "- However, even with this fix, having intersection points trail off to infinity creates a potentially large computational burden.\n",
574 | "- Fortunately there is a good solution here, will dig in next time. \n",
575 | "- Questions to think about:"
576 | ]
577 | },
578 | {
579 | "cell_type": "markdown",
580 | "metadata": {},
581 | "source": [
582 | ""
583 | ]
584 | },
585 | {
586 | "cell_type": "markdown",
587 | "metadata": {
588 | "collapsed": true
589 | },
590 | "source": [
591 | "## 1. How can we use the Hough Transform to **efficiently** find **noisy** colinear points?\n",
592 | "## 2. How might we modify the Hough Transform to avoid having intersection points at $\\infty$?"
593 | ]
594 | },
595 | {
596 | "cell_type": "markdown",
597 | "metadata": {},
598 | "source": [
599 | ""
600 | ]
601 | },
602 | {
603 | "cell_type": "markdown",
604 | "metadata": {
605 | "collapsed": true
606 | },
607 | "source": [
608 | "## Appendix A - Hough's Patent"
609 | ]
610 | },
611 | {
612 | "cell_type": "markdown",
613 | "metadata": {},
614 | "source": [
615 | "- Hough patented his idea, [published in 1962](https://patentimages.storage.googleapis.com/9f/9f/f3/87610ddec32390/US3069654.pdf).\n",
616 | "- The missing pieces from Hough's tranform would be published by other reserachers over the next 10 years, likeley making the patent not particularly useful."
617 | ]
618 | },
619 | {
620 | "cell_type": "markdown",
621 | "metadata": {},
622 | "source": [
623 | ""
624 | ]
625 | },
626 | {
627 | "cell_type": "markdown",
628 | "metadata": {},
629 | "source": [
630 | "- Hough desicribed his idea in geometrical terms in paragraphs (2) and (3) of his 1962 patent, shown above.\n",
631 | "- In my opinion, Hough's description is a bit tough to follow. However, once you understand the core idea of the Hough Transform, it's interesting to go back and review how Hough presents it - patents are often dense a tough to follow like this, so spending a little time with Hough's patent is good practice!"
632 | ]
633 | },
634 | {
635 | "cell_type": "markdown",
636 | "metadata": {},
637 | "source": [
638 | "## Appendix B - Downloading Data + Videos"
639 | ]
640 | },
641 | {
642 | "cell_type": "code",
643 | "execution_count": 3,
644 | "metadata": {
645 | "collapsed": true
646 | },
647 | "outputs": [],
648 | "source": [
649 | "#(Optional) Download data + videos if you don't have them.\n",
650 | "import os, sys\n",
651 | "sys.path.append('..')\n",
652 | "from util.get_and_unpack import get_and_unpack\n",
653 | "\n",
654 | "if not os.path.isdir('../data/'):\n",
655 | " url = 'http://www.welchlabs.io/unccv/the_original_problem/data/data.zip'\n",
656 | " get_and_unpack(url, location='..')\n",
657 | " \n",
658 | "if not os.path.isdir('../videos/'):\n",
659 | " url = 'http://www.welchlabs.io/unccv/the_original_problem/videos.zip'\n",
660 | " get_and_unpack(url, location='..') "
661 | ]
662 | }
663 | ],
664 | "metadata": {
665 | "kernelspec": {
666 | "display_name": "Python 3",
667 | "language": "python",
668 | "name": "python3"
669 | },
670 | "language_info": {
671 | "codemirror_mode": {
672 | "name": "ipython",
673 | "version": 3
674 | },
675 | "file_extension": ".py",
676 | "mimetype": "text/x-python",
677 | "name": "python",
678 | "nbconvert_exporter": "python",
679 | "pygments_lexer": "ipython3",
680 | "version": "3.7.3"
681 | }
682 | },
683 | "nbformat": 4,
684 | "nbformat_minor": 2
685 | }
686 |
--------------------------------------------------------------------------------
/papers/history_and_def_of_sobel_operator.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/papers/history_and_def_of_sobel_operator.pdf
--------------------------------------------------------------------------------
/papers/roberts_thesis.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/papers/roberts_thesis.pdf
--------------------------------------------------------------------------------
/papers/summer_vision_project.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unccv/the_original_problem/51f8899332a8aaa554eddae70ae3db9f8377c9ba/papers/summer_vision_project.pdf
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | tqdm >= 4.23.3
2 | wget >= 3.2
3 | matplotlib
4 | Pillow
5 | easydict
--------------------------------------------------------------------------------
/util/filters.py:
--------------------------------------------------------------------------------
1 | ## ------------------------- ##
2 | ##
3 | ## filter.py
4 | ## Basic image processing utilties.
5 | ##
6 | ##
7 | ## ------------------------- ##
8 | import numpy as np
9 |
10 |
11 | def roberts_cross(x):
12 | '''
13 |
14 | Compute Robert's Cross of input image x.
15 | Args: x: (nxm) grayscale floating point image
16 | Returns: (n-1) x (m-1) edge image.
17 |
18 | '''
19 |
20 | #Confirm that x is 2-dimensional
21 | if x.ndim != 2:
22 | print('Input must be 2-dimensional, not processing!')
23 | return None
24 |
25 | edges = np.zeros((x.shape[0]-1,x.shape[1]-1)) #Our output will image will be one pixel smaller than our image
26 |
27 | for i in range(x.shape[0]-1):
28 | for j in range(x.shape[1]-1):
29 | #Grab Appropriate (2x2) image patch
30 | image_patch = x[i:i+2, j:j+2]
31 | # Compute Robert's Cross for image patch
32 | edges[i, j] = np.sqrt((image_patch[0,0] - image_patch[1, 1])**2 +
33 | (image_patch[1, 0] - image_patch[0, 1])**2)
34 |
35 | return edges
36 |
37 | def filter_2d(im, kernel):
38 | '''
39 | Filter an image by taking the dot product of each
40 | image neighborhood with the kernel matrix.
41 | Args:
42 | im = (H x W) grayscale floating point image
43 | kernel = (M x N) matrix, smaller than im
44 | Returns:
45 | (H-M+1 x W-N+1) filtered image.
46 | '''
47 |
48 | M = kernel.shape[0]
49 | N = kernel.shape[1]
50 | H = im.shape[0]
51 | W = im.shape[1]
52 |
53 | filtered_image = np.zeros((H-M+1, W-N+1), dtype = 'float64')
54 |
55 | for i in range(filtered_image.shape[0]):
56 | for j in range(filtered_image.shape[1]):
57 | image_patch = im[i:i+M, j:j+N]
58 | filtered_image[i, j] = np.sum(np.multiply(image_patch, kernel))
59 |
60 | return filtered_image
61 |
62 | def make_gaussian_kernel(size, sigma):
63 | '''
64 | Create a gaussian kernel of size x size.
65 | Args:
66 | size = must be an odd positive number
67 | sigma = standard deviation of gaussian in pixels
68 | Returns: A floating point (size x size) guassian kernel
69 | '''
70 | #Make kernel of zeros:
71 | kernel = np.zeros((size, size))
72 |
73 | #Handle sigma = 0 case (will result in dividing by zero below if unchecked)
74 | if sigma == 0:
75 | return kernel
76 |
77 | #Helpful for indexing:
78 | k = int((size-1)/2)
79 |
80 | for i in range(size):
81 | for j in range(size):
82 | kernel[i, j] = (1/(2*np.pi*sigma**2))*np.exp(-((i-k)**2 + (j-k)**2)/(2*sigma**2))
83 |
84 | return kernel
85 |
--------------------------------------------------------------------------------
/util/get_and_unpack.py:
--------------------------------------------------------------------------------
1 | ## ------------------------- ##
2 | ##
3 | ## get_and_unpack.py
4 | ## Script to download and unzip data.
5 | ##
6 | ## ------------------------- ##
7 |
8 | import wget, argparse, zipfile, os
9 |
10 | def get_and_unpack(url, location='.'):
11 |
12 | #Download file
13 | print('\033[1m' + ' Downloading...this might take a little while...' + '\033[0m')
14 | filename = wget.download(url, out=location)
15 |
16 | #Unzip
17 | print('\n' + '\033[1m' + ' Unzipping...' + '\033[0m')
18 | zip_ref = zipfile.ZipFile(filename, 'r')
19 | zip_ref.extractall(path=location)
20 | zip_ref.close()
21 |
22 | #Remove zip file
23 | os.remove(filename)
24 |
25 |
26 | print('\033[1m' + 'Done!' + '\033[0m')
27 |
28 |
29 |
30 |
31 | ### --------------------------------- ###
32 | if __name__ == "__main__":
33 | parser = argparse.ArgumentParser(description='(python get_and_unpack.py -url web_address')
34 |
35 | parser.add_argument("-url", dest='url', required=True, help='web_address')
36 | args = parser.parse_args()
37 |
38 | get_and_unpack(args.url)
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/util/hough_accumulator.py:
--------------------------------------------------------------------------------
1 | ## ------------------------- ##
2 | ##
3 | ## hough_accumulator.py
4 | ## Hough acumulator class
5 | ##
6 | ##
7 | ## ------------------------- ##
8 |
9 | import numpy as np
10 |
11 |
12 | class HoughAccumulator(object):
13 | def __init__(self, theta_bins: int, phi_bins: int, phi_min: int, phi_max: int):
14 | '''
15 | Simple class to implement an accumalator for the hough transform.
16 | Args:
17 | theta_bins = number of bins to use for theta
18 | phi_bins = number of bins to use for phi
19 | phi_max = maximum phi value to accumulate
20 | phi_min = minimu phi value to acumulate
21 | '''
22 | self.theta_bins = theta_bins
23 | self.phi_bins = phi_bins
24 | self.accumulator = np.zeros((self.phi_bins, self.theta_bins))
25 |
26 | # This covers all possible lines:
27 | theta_min = 0
28 | theta_max = np.pi
29 |
30 | # Compute the phi and theta values for the grids in our accumulator:
31 | self.rhos = np.linspace(phi_min, phi_max, self.accumulator.shape[0])
32 | self.thetas = np.linspace(theta_min, theta_max, self.accumulator.shape[1])
33 |
34 | def accumulate(self, x_coords: list, y_coords: list):
35 | '''
36 | Iterate through x and y coordinates, accumulate in hough space, and return.
37 | Args:
38 | x_coords = x-coordinates of points to transform
39 | y_coords = y-coordinats of points to transform
40 |
41 | Returns:
42 | accumulator = numpy array of accumulated values.
43 | '''
44 |
45 | for i in range(len(x_coords)):
46 | # Grab a single point
47 | x = x_coords[i] # TODO This was originally called 'x_coords_scaled'. Verify if a method needs to used to scale
48 | y = y_coords[i] # TODO This was originally called 'y_coords_scaled'. Verify if a method needs to used to scale
49 |
50 | # Actually do transform!
51 | curve_prho = x * np.cos(self.thetas) + y * np.sin(self.thetas)
52 |
53 | for j in range(len(self.thetas)):
54 | # Make sure that the part of the curve falls within our accumulator
55 | if np.min(abs(curve_prho[j] - self.rhos)) <= 1.0:
56 | # Find the cell our curve goes through:
57 | rho_index = np.argmin(abs(curve_prho[j] - self.rhos))
58 | self.accumulator[rho_index, j] += 1
59 |
60 | return self.accumulator
61 |
62 | def clear_accumulator(self):
63 | '''
64 | Zero out accumulator
65 | '''
66 | self.accumulator = np.zeros((self.phi_bins, self.theta_bins))
67 |
--------------------------------------------------------------------------------
/util/image.py:
--------------------------------------------------------------------------------
1 | ## ------------------------- ##
2 | ##
3 | ## image.py
4 | ## Basic image processing utilties.
5 | ##
6 | ##
7 | ## ------------------------- ##
8 |
9 | import numpy as np
10 |
11 |
12 | def convert_to_grayscale(im):
13 | '''
14 | Convert color image to grayscale.
15 | Args: im = (nxmx3) floating point color image scaled between 0 and 1
16 | Returns: (nxm) floating point grayscale image scaled between 0 and 1
17 | '''
18 | return np.mean(im, axis = 2)
19 |
20 |
21 |
--------------------------------------------------------------------------------