diff --git a/.gitignore b/.gitignore
index 7b1094c..8a1c345 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,262 +1,229 @@
-
-# Created by https://www.gitignore.io/api/python,pycharm,eclipse,linux,osx,windows
-
-### Python ###
-# Byte-compiled / optimized / DLL files
-__pycache__/
-*.py[cod]
-*$py.class
-
-# C extensions
-*.so
-
-# Distribution / packaging
-.Python
-env/
-build/
-develop-eggs/
-dist/
-downloads/
-eggs/
-.eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
-*.egg-info/
-.installed.cfg
-*.egg
-
-# PyInstaller
-# Usually these files are written by a python script from a template
-# before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
-
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.coverage
-.coverage.*
-.cache
-nosetests.xml
-coverage.xml
-*,cover
-.hypothesis/
-
-# Translations
-*.mo
-*.pot
-
-# Django stuff:
-*.log
-local_settings.py
-
-# Flask stuff:
-instance/
-.webassets-cache
-
-# Scrapy stuff:
-.scrapy
-
-# Sphinx documentation
-docs/_build/
-
-# PyBuilder
-target/
-
-# IPython Notebook
-.ipynb_checkpoints
-
-# pyenv
-.python-version
-
-# celery beat schedule file
-celerybeat-schedule
-
-# dotenv
-.env
-
-# virtualenv
-venv/
-ENV/
-
-# Spyder project settings
-.spyderproject
-
-# Rope project settings
-.ropeproject
-
-
-### PyCharm ###
-# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
-# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
-
-# User-specific stuff:
-.idea/workspace.xml
-.idea/tasks.xml
-.idea/dictionaries
-.idea/vcs.xml
-.idea/jsLibraryMappings.xml
-
-# Sensitive or high-churn files:
-.idea/dataSources.ids
-.idea/dataSources.xml
-.idea/dataSources.local.xml
-.idea/sqlDataSources.xml
-.idea/dynamic.xml
-.idea/uiDesigner.xml
-
-# Gradle:
-.idea/gradle.xml
-.idea/libraries
-
-# Mongo Explorer plugin:
-.idea/mongoSettings.xml
-
-## File-based project format:
-*.iws
-
-## Plugin-specific files:
-
-# IntelliJ
-/out/
-
-# mpeltonen/sbt-idea plugin
-.idea_modules/
-
-# JIRA plugin
-atlassian-ide-plugin.xml
-
-# Crashlytics plugin (for Android Studio and IntelliJ)
-com_crashlytics_export_strings.xml
-crashlytics.properties
-crashlytics-build.properties
-fabric.properties
-
-### PyCharm Patch ###
-# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
-
-# *.iml
-# modules.xml
-
-
-### Eclipse ###
-
-.metadata
-bin/
-tmp/
-*.tmp
-*.bak
-*.swp
-*~.nib
-local.properties
-.settings/
-.loadpath
-.recommenders
-
-# Eclipse Core
-.project
-
-# External tool builders
-.externalToolBuilders/
-
-# Locally stored "Eclipse launch configurations"
-*.launch
-
-# PyDev specific (Python IDE for Eclipse)
-*.pydevproject
-
-# CDT-specific (C/C++ Development Tooling)
-.cproject
-
-# JDT-specific (Eclipse Java Development Tools)
-.classpath
-
-# Java annotation processor (APT)
-.factorypath
-
-# PDT-specific (PHP Development Tools)
-.buildpath
-
-# sbteclipse plugin
-.target
-
-# Tern plugin
-.tern-project
-
-# TeXlipse plugin
-.texlipse
-
-# STS (Spring Tool Suite)
-.springBeans
-
-# Code Recommenders
-.recommenders/
-
-
-### Linux ###
-*~
-
-# temporary files which can be created if a process still has a handle open of a deleted file
-.fuse_hidden*
-
-# KDE directory preferences
-.directory
-
-# Linux trash folder which might appear on any partition or disk
-.Trash-*
-
-
-### OSX ###
-*.DS_Store
-.AppleDouble
-.LSOverride
-
-# Icon must end with two \r
-Icon
-
-# Thumbnails
-._*
-
-# Files that might appear in the root of a volume
-.DocumentRevisions-V100
-.fseventsd
-.Spotlight-V100
-.TemporaryItems
-.Trashes
-.VolumeIcon.icns
-.com.apple.timemachine.donotpresent
-
-# Directories potentially created on remote AFP share
-.AppleDB
-.AppleDesktop
-Network Trash Folder
-Temporary Items
-.apdisk
-
-
-### Windows ###
-# Windows image file caches
-Thumbs.db
-ehthumbs.db
-
-# Folder config file
-Desktop.ini
-
-# Recycle Bin used on file shares
-$RECYCLE.BIN/
-
-# Windows Installer files
-*.cab
-*.msi
-*.msm
-*.msp
-
-# Windows shortcuts
-*.lnk
+
+# Created by https://www.gitignore.io/api/osx,linux,python,windows,pycharm+all
+
+### Linux ###
+*~
+
+# temporary files which can be created if a process still has a handle open of a deleted file
+.fuse_hidden*
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+# .nfs files are created when an open file is removed but is still being accessed
+.nfs*
+
+### OSX ###
+*.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+### PyCharm+all ###
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff:
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/dictionaries
+
+# Sensitive or high-churn files:
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.xml
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+
+# Gradle:
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# CMake
+cmake-build-debug/
+
+# Mongo Explorer plugin:
+.idea/**/mongoSettings.xml
+
+## File-based project format:
+*.iws
+
+## Plugin-specific files:
+
+# IntelliJ
+/out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Ruby plugin and RubyMine
+/.rakeTasks
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+### PyCharm+all Patch ###
+# Ignores the whole idea folder
+# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
+
+.idea/
+
+### Python ###
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+.pytest_cache/
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+
+# Translations
+*.mo
+*.pot
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule.*
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+
+### Windows ###
+# Windows thumbnail cache files
+Thumbs.db
+ehthumbs.db
+ehthumbs_vista.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+
+# End of https://www.gitignore.io/api/osx,linux,python,windows,pycharm+all
+/pictures/
diff --git a/.idea/.name b/.idea/.name
deleted file mode 100644
index c02165a..0000000
--- a/.idea/.name
+++ /dev/null
@@ -1 +0,0 @@
-vanishing-point-detection
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
deleted file mode 100644
index 97626ba..0000000
--- a/.idea/encodings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index 183deb0..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index dfc2113..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vanishing-point-detection.iml b/.idea/vanishing-point-detection.iml
deleted file mode 100644
index 6f63a63..0000000
--- a/.idea/vanishing-point-detection.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Testing.py b/src/Testing.py
index c087c4b..b188ddd 100644
--- a/src/Testing.py
+++ b/src/Testing.py
@@ -1,20 +1,21 @@
import os
-from VanishingPoint import *
+import cv2
-i = 0
-for subdir, dirs, files in os.walk('/pictures/input'):
+from src.vanishing_point import hough_transform, find_intersections, sample_lines, find_vanishing_point
+
+for subdir, dirs, files in os.walk('../pictures/input'):
for file in files:
filepath = subdir + os.sep + file
if filepath.endswith(".jpg"):
- i += 1
+ print(filepath)
img = cv2.imread(filepath)
hough_lines = hough_transform(img)
if hough_lines:
random_sample = sample_lines(hough_lines, 100)
- intersections = find_intersections(random_sample, img)
+ intersections = find_intersections(random_sample)
if intersections:
grid_size = min(img.shape[0], img.shape[1]) // 3
vanishing_point = find_vanishing_point(img, grid_size, intersections)
- filename = '/pictures/output/center' + str(i) + '.jpg'
+ filename = '../pictures/output/' + os.path.splitext(file)[0] + '_center' + '.jpg'
cv2.imwrite(filename, img)
diff --git a/src/VanishingPoint.py b/src/VanishingPoint.py
deleted file mode 100644
index a318224..0000000
--- a/src/VanishingPoint.py
+++ /dev/null
@@ -1,128 +0,0 @@
-import random
-
-import cv2
-import numpy as np
-
-
-# Perform edge detection
-def hough_transform(img):
- gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Convert image to grayscale
-
- kernel = np.ones((15, 15), np.uint8)
- opening = cv2.morphologyEx(gray, cv2.MORPH_OPEN, kernel) # Open (erode, then dilate)
- # cv2.imwrite('../pictures/output/opening.jpg', opening)
-
- edges = cv2.Canny(opening, 50, 150, apertureSize=3) # Canny edge detection
- # cv2.imwrite('../pictures/output/canny.jpg', edges)
-
- lines = cv2.HoughLines(edges, 1, np.pi / 180, 200) # Hough line detection
- hough_lines = []
- # Lines are represented by rho, theta; convert to endpoint notation
- if lines is not None:
- for line in lines:
- for rho, theta in line:
- a = np.cos(theta)
- b = np.sin(theta)
- x0 = a * rho
- y0 = b * rho
- x1 = int(x0 + 1000 * (-b))
- y1 = int(y0 + 1000 * (a))
- x2 = int(x0 - 1000 * (-b))
- y2 = int(y0 - 1000 * (a))
-
- cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)
- hough_lines.append(((x1, y1), (x2, y2)))
-
- # cv2.imwrite('../pictures/output/hough.jpg', img)
- return hough_lines
-
-
-# Random sampling of lines
-def sample_lines(lines, size):
- if size > len(lines):
- size = len(lines)
- return random.sample(lines, size)
-
-
-def det(a, b):
- return a[0] * b[1] - a[1] * b[0]
-
-
-# Find intersection point of two lines (not segments!)
-def line_intersection(line1, line2):
- x_diff = (line1[0][0] - line1[1][0], line2[0][0] - line2[1][0])
- y_diff = (line1[0][1] - line1[1][1], line2[0][1] - line2[1][1])
-
- div = det(x_diff, y_diff)
- if div == 0:
- return None # Lines don't cross
-
- d = (det(*line1), det(*line2))
- x = det(d, x_diff) / div
- y = det(d, y_diff) / div
-
- return x, y
-
-
-# Find intersections between multiple lines (not line segments!)
-def find_intersections(lines, img):
- intersections = []
- for i in range(len(lines)):
- line1 = lines[i]
- for j in range(i + 1, len(lines)):
- line2 = lines[j]
-
- if not line1 == line2:
- intersection = line_intersection(line1, line2)
- if intersection: # If lines cross, then add
- # Don't include intersections that happen off-image
- # Seems to cost more time than it saves
- # if not (intersection[0] < 0 or intersection[0] > img.shape[1] or
- # intersection[1] < 0 or intersection[1] > img.shape[0]):
- # print 'adding', intersection[0],intersection[1],img.shape[1],img.shape[0]
- intersections.append(intersection)
-
- return intersections
-
-
-# Given intersections, find the grid where most intersections occur and treat as vanishing point
-def find_vanishing_point(img, grid_size, intersections):
- # Image dimensions
- image_height = img.shape[0]
- image_width = img.shape[1]
-
- # Grid dimensions
- grid_rows = (image_height // grid_size) + 1
- grid_columns = (image_width // grid_size) + 1
-
- # Current cell with most intersection points
- max_intersections = 0
- best_cell = (0.0, 0.0)
-
- for i in range(grid_rows):
- for j in range(grid_columns):
- cell_left = i * grid_size
- cell_right = (i + 1) * grid_size
- cell_bottom = j * grid_size
- cell_top = (j + 1) * grid_size
- cv2.rectangle(img, (cell_left, cell_bottom), (cell_right, cell_top), (0, 0, 255), 10)
-
- current_intersections = 0 # Number of intersections in the current cell
- for x, y in intersections:
- if cell_left < x < cell_right and cell_bottom < y < cell_top:
- current_intersections += 1
-
- # Current cell has more intersections that previous cell (better)
- if current_intersections > max_intersections:
- max_intersections = current_intersections
- best_cell = ((cell_left + cell_right) / 2, (cell_bottom + cell_top) / 2)
- print(best_cell, "this best cell")
- if best_cell[0] != None and best_cell[1] != None:
- rx1 = int(best_cell[0] - grid_size / 2)
- ry1 = int(best_cell[1] - grid_size / 2)
- rx2 = int(best_cell[0] + grid_size / 2)
- ry2 = int(best_cell[1] + grid_size / 2)
- cv2.rectangle(img, (rx1, ry1), (rx2, ry2), (0, 255, 0), 10)
- # cv2.imwrite('../pictures/output/center.jpg', img)
-
- return best_cell
diff --git a/src/__init__.py b/src/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/vanishing_point.py b/src/vanishing_point.py
new file mode 100644
index 0000000..ef41f43
--- /dev/null
+++ b/src/vanishing_point.py
@@ -0,0 +1,120 @@
+import itertools
+import random
+from itertools import starmap
+
+import cv2
+import numpy as np
+
+
+# Perform edge detection
+def hough_transform(img):
+ gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Convert image to grayscale
+ kernel = np.ones((15, 15), np.uint8)
+
+ opening = cv2.morphologyEx(gray, cv2.MORPH_OPEN, kernel) # Open (erode, then dilate)
+ edges = cv2.Canny(opening, 50, 150, apertureSize=3) # Canny edge detection
+ lines = cv2.HoughLines(edges, 1, np.pi / 180, 200) # Hough line detection
+
+ hough_lines = []
+ # Lines are represented by rho, theta; converted to endpoint notation
+ if lines is not None:
+ for line in lines:
+ hough_lines.extend(list(starmap(endpoints, line)))
+
+ return hough_lines
+
+
+def endpoints(rho, theta):
+ a = np.cos(theta)
+ b = np.sin(theta)
+ x_0 = a * rho
+ y_0 = b * rho
+ x_1 = int(x_0 + 1000 * (-b))
+ y_1 = int(y_0 + 1000 * (a))
+ x_2 = int(x_0 - 1000 * (-b))
+ y_2 = int(y_0 - 1000 * (a))
+
+ return ((x_1, y_1), (x_2, y_2))
+
+
+# Random sampling of lines
+def sample_lines(lines, size):
+ if size > len(lines):
+ size = len(lines)
+ return random.sample(lines, size)
+
+
+def det(a, b):
+ return a[0] * b[1] - a[1] * b[0]
+
+
+# Find intersection point of two lines (not segments!)
+def line_intersection(line1, line2):
+ x_diff = (line1[0][0] - line1[1][0], line2[0][0] - line2[1][0])
+ y_diff = (line1[0][1] - line1[1][1], line2[0][1] - line2[1][1])
+
+ div = det(x_diff, y_diff)
+ if div == 0:
+ return None # Lines don't cross
+
+ d = (det(*line1), det(*line2))
+ x = det(d, x_diff) / div
+ y = det(d, y_diff) / div
+
+ return x, y
+
+
+# Find intersections between multiple lines (not line segments!)
+def find_intersections(lines):
+ intersections = []
+ for i, line_1 in enumerate(lines):
+ for line_2 in lines[i + 1:]:
+ if not line_1 == line_2:
+ intersection = line_intersection(line_1, line_2)
+ if intersection: # If lines cross, then add
+ intersections.append(intersection)
+
+ return intersections
+
+
+# Given intersections, find the grid where most intersections occur and treat as vanishing point
+def find_vanishing_point(img, grid_size, intersections):
+ # Image dimensions
+ image_height = img.shape[0]
+ image_width = img.shape[1]
+
+ # Grid dimensions
+ grid_rows = (image_height // grid_size) + 1
+ grid_columns = (image_width // grid_size) + 1
+
+ # Current cell with most intersection points
+ max_intersections = 0
+ best_cell = (0.0, 0.0)
+
+ for i, j in itertools.product(range(grid_rows), range(grid_columns)):
+ cell_left = i * grid_size
+ cell_right = (i + 1) * grid_size
+ cell_bottom = j * grid_size
+ cell_top = (j + 1) * grid_size
+ cv2.rectangle(img, (cell_left, cell_bottom), (cell_right, cell_top), (0, 0, 255), 10)
+
+ current_intersections = 0 # Number of intersections in the current cell
+ for x, y in intersections:
+ if cell_left < x < cell_right and cell_bottom < y < cell_top:
+ current_intersections += 1
+
+ # Current cell has more intersections that previous cell (better)
+ if current_intersections > max_intersections:
+ max_intersections = current_intersections
+ best_cell = ((cell_left + cell_right) / 2, (cell_bottom + cell_top) / 2)
+ print("Best Cell:", best_cell)
+
+ if best_cell[0] != None and best_cell[1] != None:
+ rx1 = int(best_cell[0] - grid_size / 2)
+ ry1 = int(best_cell[1] - grid_size / 2)
+ rx2 = int(best_cell[0] + grid_size / 2)
+ ry2 = int(best_cell[1] + grid_size / 2)
+ cv2.rectangle(img, (rx1, ry1), (rx2, ry2), (0, 255, 0), 10)
+ cv2.imwrite('/pictures/output/center.jpg', img)
+
+ return best_cell