Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 50 additions & 50 deletions linux/osmbundler/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
from PIL import Image
from PIL.ExifTags import TAGS

import defaults
from . import defaults

import matching
from matching import *
from . import matching
from .matching import *

import features
from features import *
from . import features
from .features import *

# a helper function to get list of photos from a directory
def getPhotosFromDirectory(photoDir):
Expand Down Expand Up @@ -47,47 +47,47 @@ class OsmBundler():
currentDir = ""

workDir = ""

# value of command line argument --photos=<..>
photosArg = ""

featureExtractor = None

matchingEngine = None

# sqlite cursor
dbCursor = None

# list of photos with focal distances for bundler input
bundlerListFile = None

# list of files with extracted features
featuresListFile = None

# information about each processed photo is stored in the following dictionary
# photo file name in self.workDir is used as the key in this dictionary
photoDict = {}

featureExtractionNeeded = True

photoScalingFactor = 0

def __init__(self):
for attr in dir(defaults):
if attr[0]!='_':
setattr(self, attr, getattr(defaults, attr))

self.parseCommandLineFlags()

# save current directory (i.e. from where RunBundler.py is called)
self.currentDir = os.getcwd()
# create a working directory
self.workDir = tempfile.mkdtemp(prefix="osm-bundler-")
logging.info("Working directory created: "+self.workDir)

if not (os.path.isdir(self.photosArg) or os.path.isfile(self.photosArg)):
raise Exception, "'%s' is neither directory nor a file name" % self.photosArg
raise Exception("'%s' is neither directory nor a file name" % self.photosArg)

# initialize mathing engine based on command line arguments
self.initMatchingEngine()

Expand Down Expand Up @@ -127,18 +127,18 @@ def parseCommandLineFlags(self):
sys.exit(2)
elif opt=="help":
self.printHelpExit()

if self.photosArg=="": self.printHelpExit()

def preparePhotos(self, *kargs, **kwargs):
# open each photo, resize, convert to pgm, copy it to self.workDir and calculate focal distance
# conversion to pgm is performed by PIL library
# EXIF reading is performed by PIL library

# open connection to cameras database
conn = sqlite3.connect(camerasDatabase)
self.dbCursor = conn.cursor()

# open list of photos with focal distances for bundler input
self.bundlerListFile = open(os.path.join(self.workDir,bundlerListFileName), "w")

Expand All @@ -152,7 +152,7 @@ def preparePhotos(self, *kargs, **kwargs):
if os.path.isdir(self.photosArg):
# directory with images
photos = getPhotosFromDirectory(self.photosArg)
if len(photos)<3: raise Exception, "The directory with images should contain at least 3 .jpg photos"
if len(photos)<3: raise Exception("The directory with images should contain at least 3 .jpg photos")
for photo in photos:
photoInfo = dict(dirname=self.photosArg, basename=photo)
self._preparePhoto(photoInfo)
Expand Down Expand Up @@ -180,7 +180,7 @@ def checkCamerasInDatabase(self):
# open connection to cameras database
conn = sqlite3.connect(camerasDatabase)
self.dbCursor = conn.cursor()

if os.path.isdir(self.photosArg):
# directory with images
photos = getPhotosFromDirectory(self.photosArg)
Expand Down Expand Up @@ -208,27 +208,27 @@ def checkCameraInDatabase(self, photoPath):
ccdWidth = self.getCcdWidthFromDatabase(exifMake, exifModel)
if ccdWidth==None:
while True:
print "Type CCD width in mm for the camera %s, %s. Press Enter to skip the camera." % (exifMake, exifModel)
userInput = raw_input("CCD width in mm: ")
print("Type CCD width in mm for the camera %s, %s. Press Enter to skip the camera." % (exifMake, exifModel))
userInput = input("CCD width in mm: ")
# Enter key was pressed
if not userInput: return
try:
ccdWidth = float(userInput)
if ccdWidth==0: raise ZeroValueException
self.dbCursor.execute("insert into cameras(make, model, ccd_width, source) values(?, ?, ?, 2)", (exifMake, exifModel, ccdWidth))
except ZeroValueException:
print "\nCCD width can not be equal to zero."
print("\nCCD width can not be equal to zero.")
except ValueError:
print "\nIncorrect value for the CCD width. Please enter CCD width in mm."
print("\nIncorrect value for the CCD width. Please enter CCD width in mm.")
except:
print "\nCan not insert CCD width to the database."
print("\nCan not insert CCD width to the database.")
else:
print "CCD width %s for the cameras %s,%s has been successively inserted to the database" % (ccdWidth, exifMake, exifModel)
print("CCD width %s for the cameras %s,%s has been successively inserted to the database" % (ccdWidth, exifMake, exifModel))
return
else:
print "Camera is already inserted into the database"
return
else:
print("Camera is already inserted into the database")
return

def _preparePhoto(self, photoInfo):
photo = photoInfo['basename']
photoDir = photoInfo['dirname']
Expand All @@ -241,7 +241,7 @@ def _preparePhoto(self, photoInfo):
# get EXIF information as a dictionary
exif = self._getExif(photoHandle)
self._calculateFocalDistance(photo, photoInfo, exif)

# resize photo if necessary
# self.photoScalingFactor takes precedence over self.maxPhotoDimension
scale = 0
Expand All @@ -255,12 +255,12 @@ def _preparePhoto(self, photoInfo):
newHeight = int(scale * photoHandle.size[1])
photoHandle = photoHandle.resize((newWidth, newHeight))
logging.info("\tCopy of the photo has been scaled down to %sx%s" % (newWidth,newHeight))

photoInfo['width'] = photoHandle.size[0]
photoInfo['height'] = photoHandle.size[1]

photoHandle.save(outputFileNameJpg)

# put photoInfo to self.photoDict
self.photoDict[photo] = photoInfo

Expand Down Expand Up @@ -288,12 +288,12 @@ def _getExif(self, photoHandle):
exif = {}
info = photoHandle._getexif()
if info:
for attr, value in info.items():
for attr, value in list(info.items()):
decodedAttr = TAGS.get(attr, attr)
if decodedAttr in exifAttrs: exif[decodedAttr] = value
if 'FocalLength' in exif: exif['FocalLength'] = float(exif['FocalLength'][0])/float(exif['FocalLength'][1])
return exif

def _calculateFocalDistance(self, photo, photoInfo, exif):
hasFocal = False
if 'Make' in exif and 'Model' in exif:
Expand Down Expand Up @@ -321,36 +321,36 @@ def initMatchingEngine(self):
matchingEngineClass = getattr(matchingEngine, matchingEngine.className)
self.matchingEngine = matchingEngineClass(os.path.join(distrPath, "software"))
except:
raise Exception, "Unable initialize matching engine %s" % self.featureExtractor
raise Exception("Unable initialize matching engine %s" % self.featureExtractor)

def initFeatureExtractor(self):
try:
featureExtractor = getattr(features, self.featureExtractor)
featureExtractorClass = getattr(featureExtractor, featureExtractor.className)
self.featureExtractor = featureExtractorClass(os.path.join(distrPath, "software"))
except:
raise Exception, "Unable initialize feature extractor %s" % self.featureExtractor
raise Exception("Unable initialize feature extractor %s" % self.featureExtractor)

def extractFeatures(self, photo):
# let self.featureExtractor do its job
os.chdir(self.workDir)
self.featureExtractor.extract(photo, self.photoDict[photo])
self.featuresListFile.write("%s.%s\n" % (photo, self.featureExtractor.fileExtension))
os.chdir(self.currentDir)

def matchFeatures(self):
# let self.matchingEngine do its job
os.chdir(self.workDir)
self.matchingEngine.match()
os.chdir(self.currentDir)


def doBundleAdjustment(self):
# just run Bundler here
logging.info("\nPerforming bundle adjustment...")
os.chdir(self.workDir)
os.mkdir("bundle")

# create options.txt
optionsFile = open("options.txt", "w")
optionsFile.writelines(defaults.bundlerOptions)
Expand All @@ -361,19 +361,19 @@ def doBundleAdjustment(self):
bundlerOutputFile.close()
os.chdir(self.currentDir)
logging.info("Finished! See the results in the '%s' directory" % self.workDir)

def printHelpExit(self):
self.printHelp()
sys.exit(2)

def openResult(self):
if sys.platform == "win32": subprocess.call(["explorer", self.workDir])
if sys.platform == "linux2": subprocess.call(["xdg-open", self.workDir])
else: print "Thanks"
if sys.platform == "linux2": subprocess.call(["xdg-open", self.workDir])
else: print("Thanks")

def printHelp(self):
helpFile = open(os.path.join(distrPath, "osmbundler/help.txt"), "r")
print helpFile.read()
print(helpFile.read())
helpFile.close()

# a helper function to get CCD width from sqlite database
Expand Down
2 changes: 1 addition & 1 deletion linux/osmbundler/features/sift.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import sys, os, logging

from extractor import FeatureExtractor
from .extractor import FeatureExtractor

class Sift(FeatureExtractor):

Expand Down
2 changes: 1 addition & 1 deletion linux/osmbundler/features/siftlowe.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os, subprocess, gzip

from sift import Sift
from .sift import Sift

className = "LoweSift"
class LoweSift(Sift):
Expand Down
14 changes: 6 additions & 8 deletions linux/osmbundler/features/siftvlfeat.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import os, subprocess, gzip, logging

from sift import Sift
from .sift import Sift

className = "VlfeatSift"
class VlfeatSift(Sift):

win32Executable = "vlfeat/bin/w32/sift.exe"
linuxExecutable = "vlfeat/bin/glx/sift"

Expand All @@ -20,19 +20,17 @@ def extract(self, photo, photoInfo):
featureStrings = vlfeatTextFile.readlines()
numFeatures = len(featureStrings)
# write header
loweGzipFile.write("%s 128\n" % numFeatures)
loweGzipFile.write(("%s 128\n" % numFeatures).encode())
for featureString in featureStrings:
features = featureString.split()
# swap features[0] and features[1]
tmp = features[0]
features[0] = features[1]
features[1] = tmp
features[1], features[0] = features[0:2]
i1 = 0
for i2 in (4,24,44,64,84,104,124,132):
loweGzipFile.write("%s\n" % " ".join(features[i1:i2]))
loweGzipFile.write(("%s\n" % " ".join(features[i1:i2])).encode())
i1 = i2
loweGzipFile.close()
vlfeatTextFile.close()
# remove original SIFT file
os.remove("%s.key" % photo)
logging.info("\tFound %s features" % numFeatures)
logging.info("\tFound %s features" % numFeatures)
2 changes: 1 addition & 1 deletion linux/osmbundler/matching/bundler.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import sys,os,subprocess,logging

from engine import MatchingEngine
from .engine import MatchingEngine

className = "BundlerMatching"
class BundlerMatching(MatchingEngine):
Expand Down
2 changes: 1 addition & 1 deletion linux/osmbundler/matching/manual.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from engine import MatchingEngine
from .engine import MatchingEngine

className = "ManualMatching"
class ManualMatching(MatchingEngine):
Expand Down
Loading